11#include <xcb/xcb_image.h>
12#include <xcb/render.h>
13#include <xcb/xcb_renderutil.h>
26#include <QtGui/private/qhighdpiscaling_p.h>
27#include <qpa/qplatformgraphicsbuffer.h>
28#include <private/qimage_p.h>
33#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1
60 bool hasShm()
const {
return m_shm_info.shmaddr !=
nullptr; }
66 xcb_shm_segment_info_t *shm_info =
nullptr);
71 void createShmSegment(
size_t segmentSize);
72 void destroyShmSegment();
73 void destroy(
bool destroyShm);
75 void ensureGC(xcb_drawable_t
dst);
77 void flushPixmap(
const QRegion ®ion,
bool fullRegion =
false);
78 void setClip(
const QRegion ®ion);
80 xcb_shm_segment_info_t m_shm_info;
81 size_t m_segmentSize = 0;
84 xcb_image_t *m_xcb_image =
nullptr;
89 xcb_gcontext_t m_gc = 0;
90 xcb_drawable_t m_gc_drawable = 0;
97 xcb_pixmap_t m_xcb_pixmap = 0;
110 bool m_hasAlpha =
false;
111 bool m_clientSideScroll =
false;
113 const xcb_format_t *m_xcb_format =
nullptr;
144 QImage *m_image =
nullptr;
149 return static_cast<size_t>(
image->stride) *
image->height;
154 , m_backingStore(backingStore)
163 , m_backingStore(backingStore)
178 memset(&m_shm_info, 0,
sizeof m_shm_info);
188 : XCB_IMAGE_ORDER_LSB_FIRST;
189 m_xcb_image = xcb_image_create(
size.width(),
size.height(),
190 XCB_IMAGE_FORMAT_Z_PIXMAP,
191 m_xcb_format->scanline_pad,
193 m_xcb_format->bits_per_pixel,
195 XCB_IMAGE_ORDER_MSB_FIRST,
196 nullptr, ~0,
nullptr);
201 if (segmentSize == 0) {
202 if (m_segmentSize > 0) {
205 <<
"] destroyed SHM segment due to resize to" <<
size;
211 if (m_shm_info.shmaddr && (m_segmentSize < segmentSize || m_segmentSize / 2 >= segmentSize))
213 if (!m_shm_info.shmaddr) {
215 <<
"] creating shared memory" << segmentSize <<
"bytes for"
216 <<
size <<
"depth" << m_xcb_format->depth <<
"bits"
217 << m_xcb_format->bits_per_pixel;
218 createShmSegment(segmentSize);
223 if (segmentSize == 0)
226 m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize);
227 m_qimage =
QImage(
static_cast<uchar *
>(m_xcb_image->data), m_xcb_image->width,
228 m_xcb_image->height, m_xcb_image->stride, m_qimage_format);
237 m_xcb_image->width, m_xcb_image->height);
240void QXcbBackingStoreImage::destroy(
bool destroyShm)
243 if (m_xcb_image->data) {
244 if (m_shm_info.shmaddr) {
248 free(m_xcb_image->data);
251 xcb_image_destroy(m_xcb_image);
260 delete m_graphics_buffer;
261 m_graphics_buffer =
nullptr;
273 if (m_clientSideScroll == clientSideScroll)
276 m_clientSideScroll = clientSideScroll;
278 if (m_scrolledRegion.
isNull())
286 if (m_clientSideScroll) {
288 for (
const QRect &
rect : m_scrolledRegion) {
289 const int w =
rect.width();
290 const int h =
rect.height();
300 if (
reply &&
reply->depth == m_xcb_image->depth) {
311 ensureGC(m_xcb_pixmap);
313 shmPutImage(m_xcb_pixmap, m_scrolledRegion);
315 flushPixmap(m_scrolledRegion,
true);
319void QXcbBackingStoreImage::createShmSegment(
size_t segmentSize)
326 if (
Q_UNLIKELY(segmentSize > std::numeric_limits<uint32_t>::max())) {
327 qCWarning(lcQpaXcb,
"xcb_shm_create_segment() can't be called for size %zu, maximum"
328 "allowed size is %u", segmentSize, std::numeric_limits<uint32_t>::max());
336 qCWarning(lcQpaXcb,
"xcb_shm_create_segment() failed for size %zu", segmentSize);
341 if (
reply->nfd != 1) {
342 for (
int i = 0;
i <
reply->nfd;
i++)
345 qCWarning(lcQpaXcb,
"failed to get file descriptor for shm segment of size %zu", segmentSize);
349 void *
addr = mmap(
nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED,
fds[0], 0);
351 qCWarning(lcQpaXcb,
"failed to mmap segment from X server (%d: %s) for size %zu",
352 errno, strerror(errno), segmentSize);
359 m_shm_info.shmseg = seg;
360 m_shm_info.shmaddr =
static_cast<quint8 *
>(
addr);
361 m_segmentSize = segmentSize;
366 m_segmentSize = segmentSize;
371 xcb_shm_segment_info_t *shmInfo)
373 const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600);
375 qCWarning(lcQpaXcb,
"shmget() failed (%d: %s) for size %zu", errno, strerror(errno), segmentSize);
379 void *
addr = shmat(
id,
nullptr, 0);
380 if (
addr == (
void *)-1) {
381 qCWarning(lcQpaXcb,
"shmat() failed (%d: %s) for id %d", errno, strerror(errno),
id);
385 if (shmctl(
id, IPC_RMID,
nullptr) == -1)
386 qCWarning(lcQpaXcb,
"Error while marking the shared memory segment to be destroyed");
388 const auto seg = xcb_generate_id(
c);
389 auto cookie = xcb_shm_attach_checked(
c, seg,
id,
false);
390 auto *
error = xcb_request_check(
c, cookie);
392 qCWarning(lcQpaXcb(),
"xcb_shm_attach() failed");
394 if (shmdt(
addr) == -1)
395 qCWarning(lcQpaXcb,
"shmdt() failed (%d: %s) for %p", errno, strerror(errno),
addr);
397 }
else if (!shmInfo) {
398 xcb_shm_detach(
c, seg);
400 if (shmdt(shmaddr) == -1)
401 qCWarning(lcQpaXcb,
"shmdt() failed (%d: %s) for %p", errno, strerror(errno), shmaddr);
404 shmInfo->shmseg = seg;
406 shmInfo->shmaddr =
static_cast<quint8 *
>(
addr);
411void QXcbBackingStoreImage::destroyShmSegment()
413 auto cookie = xcb_shm_detach_checked(
xcb_connection(), m_shm_info.shmseg);
417 m_shm_info.shmseg = 0;
421 if (munmap(m_shm_info.shmaddr, m_segmentSize) == -1) {
422 qCWarning(lcQpaXcb,
"munmap() failed (%d: %s) for %p with size %zu",
423 errno, strerror(errno), m_shm_info.shmaddr, m_segmentSize);
428 if (shmdt(m_shm_info.shmaddr) == -1) {
429 qCWarning(lcQpaXcb,
"shmdt() failed (%d: %s) for %p",
430 errno, strerror(errno), m_shm_info.shmaddr);
432 m_shm_info.shmid = 0;
434 m_shm_info.shmaddr =
nullptr;
445 const QPoint delta(dx, dy);
446 const QRegion destinationRegion =
scrollArea.translated(delta).intersected(bounds);
448 if (m_clientSideScroll) {
458 ensureGC(m_xcb_pixmap);
462 shmPutImage(m_xcb_pixmap, partialFlushRegion);
463 m_pendingFlush -= partialFlushRegion;
476 dst.width(),
dst.height());
480 m_pendingFlush -= destinationRegion;
483 m_scrolledRegion |= destinationRegion;
488void QXcbBackingStoreImage::ensureGC(xcb_drawable_t
dst)
490 if (m_gc_drawable !=
dst) {
494 static const uint32_t
mask = XCB_GC_GRAPHICS_EXPOSURES;
495 static const uint32_t
values[] = { 0 };
506 const uchar *srcData =
img.constBits();
512 for (
int yy =
rect.top(); yy <
bottom; ++yy) {
514 ::memmove(
dst,
src, dstBytesPerLine);
515 dst += dstBytesPerLine;
519template <
class Pixel>
522 const uchar *srcData =
img.constBits();
529 for (
int yy =
rect.top(); yy <
bottom; ++yy) {
531 const Pixel *srcPixels =
reinterpret_cast<const Pixel *
>(srcData + yy * srcBytesPerLine) +
left;
534 dstPixels[
i] = qbswap<Pixel>(*srcPixels++);
542 if (!
swap &&
src.rect() ==
rect &&
src.bytesPerLine() == dstStride)
548 switch (
src.depth()) {
565 return (
base + pad - 1) & -pad;
568void QXcbBackingStoreImage::shmPutImage(xcb_drawable_t drawable,
const QRegion ®ion,
const QPoint &
offset)
584 m_xcb_image->data - m_shm_info.shmaddr);
589void QXcbBackingStoreImage::flushPixmap(
const QRegion ®ion,
bool fullRegion)
592 auto actualRegion = m_pendingFlush.
intersected(region);
593 m_pendingFlush -= region;
594 flushPixmap(actualRegion,
true);
598 xcb_image_t xcb_subimage;
599 memset(&xcb_subimage, 0,
sizeof(xcb_image_t));
601 xcb_subimage.format = m_xcb_image->format;
602 xcb_subimage.scanline_pad = m_xcb_image->scanline_pad;
603 xcb_subimage.depth = m_xcb_image->depth;
604 xcb_subimage.bpp = m_xcb_image->bpp;
605 xcb_subimage.unit = m_xcb_image->unit;
606 xcb_subimage.plane_mask = m_xcb_image->plane_mask;
607 xcb_subimage.byte_order = (xcb_image_order_t)
connection()->
setup()->image_byte_order;
608 xcb_subimage.bit_order = m_xcb_image->bit_order;
610 const bool needsByteSwap = xcb_subimage.byte_order != m_xcb_image->byte_order;
616 const int rows_per_put = maxPutImageRequestDataBytes /
stride;
628 const int x =
rect.x();
634 const int rows = std::min(
height, rows_per_put);
640 xcb_subimage.width =
width;
641 xcb_subimage.height = rows;
642 xcb_subimage.data =
const_cast<uint8_t *
>(subImage.
constBits());
643 xcb_image_annotate(&xcb_subimage);
659void QXcbBackingStoreImage::setClip(
const QRegion ®ion)
662 static const uint32_t
mask = XCB_GC_CLIP_MASK;
663 static const uint32_t
values[] = { XCB_NONE };
668 XCB_CLIP_ORDERING_YX_BANDED,
671 xcb_rects.size(), xcb_rects.constData());
686 for (
const QRect &
rect : scrolledRegion) {
698 const QRegion notScrolledArea = region - scrolledRegion;
699 shmPutImage(
dst, notScrolledArea,
offset);
734 m_scrolledRegion -= region;
735 m_pendingFlush |= region;
740 auto info =
reinterpret_cast<xcb_shm_segment_info_t *
>(shmInfo);
776 p.fillRect(
rect, blank);
797 const auto end = region.
end();
850 if (!platformWindow) {
869 qreal sourceDevicePixelRatio,
873 bool translucentBackground)
918 if (
win->imageNeedsRgbSwap()) {
949 platformWindow->setParentRelativeBackPixmap();
951 m_useGrabbedBackgound = !m_usingXRenderMode;
957 if (m_xrenderPicture) {
959 m_xrenderPicture = XCB_NONE;
961 if (m_xrenderPixmap) {
963 m_xrenderPixmap = XCB_NONE;
965 if (m_windowPicture) {
967 m_windowPicture = XCB_NONE;
975 if (m_useGrabbedBackgound) {
979 p.drawPixmap(
rect, m_grabbedBackground,
rect);
985 if (!m_usingXRenderMode) {
997 m_xrenderPicture, 0, m_windowPicture,
1004 if (!m_usingXRenderMode) {
1007 if (m_useGrabbedBackgound) {
1010 m_grabbedBackground =
win->xcbScreen()->grabWindow(
win->
winId(), 0, 0,
1016 if (m_xrenderPicture) {
1018 m_xrenderPicture = XCB_NONE;
1020 if (m_xrenderPixmap) {
1022 m_xrenderPixmap = XCB_NONE;
1031 xcb_render_create_picture(
xcb_connection(), m_xrenderPicture, m_xrenderPixmap, m_xrenderPictFormat, 0,
nullptr);
1040void QXcbSystemTrayBackingStore::initXRenderMode()
1046 auto formatsReply =
Q_XCB_REPLY(xcb_render_query_pict_formats, conn);
1048 if (!formatsReply) {
1049 qWarning(
"QXcbSystemTrayBackingStore: xcb_render_query_pict_formats() failed");
1053 xcb_render_pictforminfo_t *
fmt = xcb_render_util_find_standard_format(formatsReply.get(),
1054 XCB_PICT_STANDARD_ARGB_32);
1056 qWarning(
"QXcbSystemTrayBackingStore: Failed to find format PICT_STANDARD_ARGB_32");
1060 m_xrenderPictFormat =
fmt->id;
1063 xcb_render_pictvisual_t *vfmt = xcb_render_util_find_visual_format(formatsReply.get(), platformWindow->visualId());
1066 qWarning(
"QXcbSystemTrayBackingStore: Failed to find format for visual %x", platformWindow->visualId());
1070 m_windowPicture = xcb_generate_id(conn);
1071 xcb_void_cookie_t cookie =
1072 xcb_render_create_picture_checked(conn, m_windowPicture, platformWindow->xcb_window(), vfmt->format, 0,
nullptr);
1073 xcb_generic_error_t *
error = xcb_request_check(conn, cookie);
1075 qWarning(
"QXcbSystemTrayBackingStore: Failed to create Picture with format %x for window %x, error code %d",
1076 vfmt->format, platformWindow->xcb_window(),
error->error_code);
1081 m_usingXRenderMode =
true;
The QColor class provides colors based on RGB, HSV or CMYK values.
static QPixelFormat toPixelFormat(QImage::Format format) noexcept
Converts format into a QPixelFormat.
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
qsizetype sizeInBytes() const
QSize size() const
Returns the size of the image, i.e.
uchar * bits()
Returns a pointer to the first pixel data.
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Format
The following image formats are available in Qt.
@ Format_ARGB32_Premultiplied
QImage rgbSwapped() const &
Format format() const
Returns the format of the image.
const uchar * constBits() const
Returns a pointer to the first pixel data.
bool isEmpty() const noexcept
The QPainter class performs low-level painting on widgets and other paint devices.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
QRect intersected(const QRect &other) const noexcept
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr QRect translated(int dx, int dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
The QRegion class specifies a clip region for a painter.
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
bool intersects(const QRegion &r) const
const_iterator end() const noexcept
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
const_iterator begin() const noexcept
QRegion intersected(const QRegion &r) const
QRegion translated(int dx, int dy) const
QPlatformScreen * handle() const
Get the platform screen handle.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
T pop()
Removes the top item from the stack and returns it.
void push(const T &t)
Adds element t to the top of the stack.
int x
the x position of the window's geometry
QSize size() const override
Returns the size of the window excluding any window frame.
void flushScrolledRegion(bool clientSideScroll)
QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size)
void put(xcb_drawable_t dst, const QRegion ®ion, const QPoint &offset)
void resize(const QSize &size)
void preparePaint(const QRegion ®ion)
QPlatformGraphicsBuffer * graphicsBuffer()
bool scroll(const QRegion &area, int dx, int dy)
static bool createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize=1, xcb_shm_segment_info_t *shm_info=nullptr)
QXcbBackingStoreImage * m_image
QPlatformGraphicsBuffer * graphicsBuffer() const override
Accessor for a backingstores graphics buffer abstraction.
void resize(const QSize &size, const QRegion &staticContents) override
FlushResult rhiFlush(QWindow *window, qreal sourceDevicePixelRatio, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground) override
Flushes the given region from the specified window, and compositing it with the specified textures li...
QPaintDevice * paintDevice() override
Implement this function to return the appropriate paint device.
QXcbBackingStore(QWindow *window)
void endPaint() override
This function is called after painting onto the surface has ended.
virtual void render(xcb_window_t window, const QRegion ®ion, const QPoint &offset)
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override
Flushes the given region from the specified window.
void beginPaint(const QRegion &) override
This function is called before painting onto the surface begins, with the region in which the paintin...
virtual void recreateImage(QXcbWindow *win, const QSize &size)
QStack< QRegion > m_paintRegions
static bool createSystemVShmSegment(xcb_connection_t *c, size_t segmentSize=1, void *shmInfo=nullptr)
QImage toImage() const override
Implemented in subclasses to return the content of the backingstore as a QImage.
bool scroll(const QRegion &area, int dx, int dy) override
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
size_t maxRequestDataBytes(size_t requestSize) const
const xcb_setup_t * setup() const
void printXcbError(const char *message, xcb_generic_error_t *error)
QXcbScreen * primaryScreen() const
const xcb_format_t * formatForDepth(uint8_t depth) const
uchar * data() override
Accessor for the bytes of the buffer.
QXcbGraphicsBuffer(QImage *image)
const uchar * data() const override
Accessor for the bytes of the buffer.
int bytesPerLine() const override
Accessor for bytes per line in the graphics buffer.
Origin origin() const override
In origin of the content of the graphics buffer.
bool doLock(AccessTypes access, const QRect &rect) override
This function should be reimplemented by subclasses.
void doUnlock() override
This function should remove all locks set on the buffer.
QXcbConnection * connection() const
xcb_connection_t * xcb_connection() const
void setConnection(QXcbConnection *connection)
quint8 depthOfVisual(xcb_visualid_t visualid) const
~QXcbSystemTrayBackingStore()
void render(xcb_window_t window, const QRegion ®ion, const QPoint &offset) override
void beginPaint(const QRegion &) override
This function is called before painting onto the surface begins, with the region in which the paintin...
void recreateImage(QXcbWindow *win, const QSize &size) override
QXcbSystemTrayBackingStore(QWindow *window)
xcb_window_t xcb_window() const
void updateSyncRequestCounter()
bool imageNeedsRgbSwap() const
EGLint EGLint EGLint EGLint int int int int * fds
QSet< QString >::iterator it
T toNativePixels(const T &value, const C *context)
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
DBusConnection * connection
static int area(const QSize &s)
QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
static const double leftOffset
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLsizei GLsizei GLint * values
[15]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint const GLuint GLuint const GLuint * textures
const void GLsizei GLsizei stride
GLenum GLuint GLintptr offset
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
QVideoFrameFormat::PixelFormat fmt
static void copy_swapped(char *dst, const int dstStride, const QImage &img, const QRect &rect)
void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
static QImage native_sub_image(QByteArray *buffer, const int dstStride, const QImage &src, const QRect &rect, bool swap)
static quint32 round_up_scanline(quint32 base, quint32 pad)
static void copy_unswapped(char *dst, int dstBytesPerLine, const QImage &img, const QRect &rect)
static size_t imageDataSize(const xcb_image_t *image)
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)
QList< xcb_rectangle_t > qRegionToXcbRectangleList(const QRegion ®ion)
QFileInfo info(fileName)
[8]