diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.cpp | 205 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.h | 31 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 9 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp | 29 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbsystemtraytracker.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 10 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 3 | ||||
-rw-r--r-- | src/widgets/util/qsystemtrayicon_x11.cpp | 43 |
8 files changed, 261 insertions, 71 deletions
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index b81cb8efa1..e73e6f3e61 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -45,6 +45,16 @@ #include <xcb/shm.h> #include <xcb/xcb_image.h> +#if QT_CONFIG(xcb_render) +#include <xcb/render.h> +// 'template' is used as a function argument name in xcb_renderutil.h +#define template template_param +// extern "C" is missing too +extern "C" { +#include <xcb/xcb_renderutil.h> +} +#undef template +#endif #include <sys/ipc.h> #include <sys/shm.h> @@ -75,7 +85,7 @@ class QXcbBackingStore; class QXcbBackingStoreImage : public QXcbObject { public: - QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size); + QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format); ~QXcbBackingStoreImage() { destroy(true); } void resize(const QSize &size); @@ -110,8 +120,9 @@ private: void flushPixmap(const QRegion ®ion, bool fullRegion = false); void setClip(const QRegion ®ion); + xcb_window_t m_screen_root; + xcb_shm_segment_info_t m_shm_info; - QXcbBackingStore *m_backingStore = nullptr; size_t m_segmentSize = 0; xcb_image_t *m_xcb_image = nullptr; @@ -179,17 +190,15 @@ static inline size_t imageDataSize(const xcb_image_t *image) return static_cast<size_t>(image->stride) * image->height; } -QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size) - : QXcbObject(backingStore->connection()) - , m_backingStore(backingStore) +QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) + : QXcbObject(screen->connection()) + , m_screen_root(screen->screen()->root) { - QXcbWindow *window = static_cast<QXcbWindow *>(backingStore->window()->handle()); - const xcb_format_t *fmt = connection()->formatForDepth(window->depth()); + const xcb_format_t *fmt = connection()->formatForDepth(depth); Q_ASSERT(fmt); memset(&m_shm_info, 0, sizeof m_shm_info); - QImage::Format format = window->imageFormat(); m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; if (!m_hasAlpha) create(size, fmt, qt_maybeAlphaVersionWithSameDepth(format)); @@ -238,11 +247,10 @@ void QXcbBackingStoreImage::create(const QSize &size, const xcb_format_t *fmt, Q m_graphics_buffer = new QXcbGraphicsBuffer(&m_qimage); m_xcb_pixmap = xcb_generate_id(xcb_connection()); - auto xcbScreen = static_cast<QXcbScreen *>(m_backingStore->window()->screen()->handle()); xcb_create_pixmap(xcb_connection(), m_xcb_image->depth, m_xcb_pixmap, - xcbScreen->root(), + m_screen_root, m_xcb_image->width, m_xcb_image->height); } @@ -832,7 +840,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin return; } - m_image->put(platformWindow->xcb_window(), clipped, offset); + render(platformWindow->xcb_window(), clipped, offset); if (platformWindow->needsSync()) platformWindow->updateSyncRequestCounter(); @@ -840,6 +848,11 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin xcb_flush(xcb_connection()); } +void QXcbBackingStore::render(xcb_window_t window, const QRegion ®ion, const QPoint &offset) +{ + m_image->put(window, region, offset); +} + #ifndef QT_NO_OPENGL void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, @@ -873,10 +886,15 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &) } QXcbWindow* win = static_cast<QXcbWindow *>(pw); + recreateImage(win, size); +} + +void QXcbBackingStore::recreateImage(QXcbWindow *win, const QSize &size) +{ if (m_image) m_image->resize(size); else - m_image = new QXcbBackingStoreImage(this, size); + m_image = new QXcbBackingStoreImage(win->xcbScreen(), size, win->depth(), win->imageFormat()); // Slow path for bgr888 VNC: Create an additional image, paint into that and // swap R and B while copying to m_image after each paint. @@ -893,4 +911,167 @@ bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) return false; } +QXcbSystemTrayBackingStore::QXcbSystemTrayBackingStore(QWindow *window) + : QXcbBackingStore(window) +{ + // We need three different behaviors depending on whether the X11 visual + // for the system tray supports an alpha channel, i.e. is 32 bits, and + // whether XRender can be used: + // 1) if the visual has an alpha channel, then render the window's buffer + // directly to the X11 window as usual + // 2) else if XRender can be used, then render the window's buffer to Pixmap, + // then render Pixmap's contents to the cleared X11 window with + // xcb_render_composite() + // 3) else grab the X11 window's content and paint it first each time as a + // background before rendering the window's buffer to the X11 window + + auto *platformWindow = static_cast<QXcbWindow *>(window->handle()); + quint8 depth = connection()->primaryScreen()->depthOfVisual(platformWindow->visualId()); + + if (depth != 32) { + platformWindow->setParentRelativeBackPixmap(); +#if QT_CONFIG(xcb_render) + initXRenderMode(); +#endif + m_useGrabbedBackgound = !m_usingXRenderMode; + } +} + +QXcbSystemTrayBackingStore::~QXcbSystemTrayBackingStore() +{ +#if QT_CONFIG(xcb_render) + if (m_xrenderPicture) { + xcb_render_free_picture(xcb_connection(), m_xrenderPicture); + m_xrenderPicture = XCB_NONE; + } + if (m_xrenderPixmap) { + xcb_free_pixmap(xcb_connection(), m_xrenderPixmap); + m_xrenderPixmap = XCB_NONE; + } + if (m_windowPicture) { + xcb_render_free_picture(xcb_connection(), m_windowPicture); + m_windowPicture = XCB_NONE; + } +#endif // QT_CONFIG(xcb_render) +} + +void QXcbSystemTrayBackingStore::beginPaint(const QRegion ®ion) +{ + QXcbBackingStore::beginPaint(region); + + if (m_useGrabbedBackgound) { + QPainter p(paintDevice()); + p.setCompositionMode(QPainter::CompositionMode_Source); + for (const QRect &rect: region) + p.drawPixmap(rect, m_grabbedBackground, rect); + } +} + +void QXcbSystemTrayBackingStore::render(xcb_window_t window, const QRegion ®ion, const QPoint &offset) +{ + if (!m_usingXRenderMode) { + QXcbBackingStore::render(window, region, offset); + return; + } + +#if QT_CONFIG(xcb_render) + m_image->put(m_xrenderPixmap, region, offset); + const QRect bounds = region.boundingRect(); + const QPoint target = bounds.topLeft(); + const QRect source = bounds.translated(offset); + xcb_clear_area(xcb_connection(), false, window, + target.x(), target.y(), source.width(), source.height()); + xcb_render_composite(xcb_connection(), XCB_RENDER_PICT_OP_OVER, + m_xrenderPicture, 0, m_windowPicture, + target.x(), target.y(), 0, 0, target.x(), target.y(), + source.width(), source.height()); +#endif // QT_CONFIG(xcb_render) +} + +void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &size) +{ + if (!m_usingXRenderMode) { + QXcbBackingStore::recreateImage(win, size); + + if (m_useGrabbedBackgound) { + xcb_clear_area(xcb_connection(), false, win->xcb_window(), + 0, 0, size.width(), size.height()); + m_grabbedBackground = win->xcbScreen()->grabWindow(win->winId(), 0, 0, + size.width(), size.height()); + } + return; + } + +#if QT_CONFIG(xcb_render) + if (m_xrenderPicture) { + xcb_render_free_picture(xcb_connection(), m_xrenderPicture); + m_xrenderPicture = XCB_NONE; + } + if (m_xrenderPixmap) { + xcb_free_pixmap(xcb_connection(), m_xrenderPixmap); + m_xrenderPixmap = XCB_NONE; + } + + QXcbScreen *screen = win->xcbScreen(); + + m_xrenderPixmap = xcb_generate_id(xcb_connection()); + xcb_create_pixmap(xcb_connection(), 32, m_xrenderPixmap, screen->root(), size.width(), size.height()); + + m_xrenderPicture = xcb_generate_id(xcb_connection()); + xcb_render_create_picture(xcb_connection(), m_xrenderPicture, m_xrenderPixmap, m_xrenderPictFormat, 0, 0); + + // XRender expects premultiplied alpha + if (m_image) + m_image->resize(size); + else + m_image = new QXcbBackingStoreImage(screen, size, 32, QImage::Format_ARGB32_Premultiplied); +#endif // QT_CONFIG(xcb_render) +} + +#if QT_CONFIG(xcb_render) +void QXcbSystemTrayBackingStore::initXRenderMode() +{ + if (!connection()->hasXRender()) + return; + + xcb_connection_t *conn = xcb_connection(); + auto formatsReply = Q_XCB_REPLY(xcb_render_query_pict_formats, conn); + + if (!formatsReply) { + qWarning("QXcbSystemTrayBackingStore: xcb_render_query_pict_formats() failed"); + return; + } + + xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply.get(), + XCB_PICT_STANDARD_ARGB_32); + if (!fmt) { + qWarning("QXcbSystemTrayBackingStore: Failed to find format PICT_STANDARD_ARGB_32"); + return; + } + + m_xrenderPictFormat = fmt->id; + + auto *platformWindow = static_cast<QXcbWindow *>(window()->handle()); + xcb_render_pictvisual_t *vfmt = xcb_render_util_find_visual_format(formatsReply.get(), platformWindow->visualId()); + + if (!vfmt) { + qWarning("QXcbSystemTrayBackingStore: Failed to find format for visual %x", platformWindow->visualId()); + return; + } + + m_windowPicture = xcb_generate_id(conn); + xcb_void_cookie_t cookie = + xcb_render_create_picture_checked(conn, m_windowPicture, platformWindow->xcb_window(), vfmt->format, 0, 0); + xcb_generic_error_t *error = xcb_request_check(conn, cookie); + if (error) { + qWarning("QXcbSystemTrayBackingStore: Failed to create Picture with format %x for window %x, error code %d", + vfmt->format, platformWindow->xcb_window(), error->error_code); + free(error); + return; + } + + m_usingXRenderMode = true; +} +#endif // QT_CONFIG(xcb_render) + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 734de1f7d7..39d023cb9d 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -77,12 +77,41 @@ public: static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, void *shmInfo = nullptr); -private: +protected: + virtual void render(xcb_window_t window, const QRegion ®ion, const QPoint &offset); + virtual void recreateImage(QXcbWindow *win, const QSize &size); + QXcbBackingStoreImage *m_image = nullptr; QStack<QRegion> m_paintRegions; QImage m_rgbImage; }; +class QXcbSystemTrayBackingStore : public QXcbBackingStore +{ +public: + QXcbSystemTrayBackingStore(QWindow *window); + ~QXcbSystemTrayBackingStore(); + + void beginPaint(const QRegion &) override; + +protected: + void render(xcb_window_t window, const QRegion ®ion, const QPoint &offset) override; + void recreateImage(QXcbWindow *win, const QSize &size) override; + +private: +#if QT_CONFIG(xcb_render) + void initXRenderMode(); + + xcb_pixmap_t m_xrenderPixmap = XCB_NONE; + xcb_render_picture_t m_xrenderPicture = XCB_NONE; + xcb_render_pictformat_t m_xrenderPictFormat = XCB_NONE; + xcb_render_picture_t m_windowPicture = XCB_NONE; +#endif + bool m_usingXRenderMode = false; + bool m_useGrabbedBackgound = false; + QPixmap m_grabbedBackground; +}; + QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 49649eb816..d873d26ebd 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -241,7 +241,8 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle()); QXcbGlIntegration *glIntegration = screen->connection()->glIntegration(); - if (window->type() != Qt::Desktop) { + const bool isTrayIconWindow = window->objectName() == QLatin1String("QSystemTrayIconSysWindow"); + if (window->type() != Qt::Desktop && !isTrayIconWindow) { if (window->supportsOpenGL()) { if (glIntegration) { QXcbWindow *xcbWindow = glIntegration->createWindow(window); @@ -257,7 +258,7 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const } } - Q_ASSERT(window->type() == Qt::Desktop || !window->supportsOpenGL() + Q_ASSERT(window->type() == Qt::Desktop || isTrayIconWindow || !window->supportsOpenGL() || (!glIntegration && window->surfaceType() == QSurface::RasterGLSurface)); // for VNC QXcbWindow *xcbWindow = new QXcbWindow(window); xcbWindow->create(); @@ -284,6 +285,10 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const { + const bool isTrayIconWindow = window->objectName() == QLatin1String("QSystemTrayIconSysWindow"); + if (isTrayIconWindow) + return new QXcbSystemTrayBackingStore(window); + #if QT_CONFIG(xcb_native_painting) if (nativePaintingEnabled()) return new QXcbNativeBackingStore(window); diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index c98879c7df..8b9c67e98a 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -162,10 +162,28 @@ void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_ev } } +xcb_visualid_t QXcbSystemTrayTracker::visualId() +{ + xcb_visualid_t visual = netSystemTrayVisual(); + if (visual == XCB_NONE) + visual = m_connection->primaryScreen()->screen()->root_visual; + return visual; +} + bool QXcbSystemTrayTracker::visualHasAlphaChannel() { + const xcb_visualid_t systrayVisualId = netSystemTrayVisual(); + if (systrayVisualId != XCB_NONE) { + quint8 depth = m_connection->primaryScreen()->depthOfVisual(systrayVisualId); + return depth == 32; + } + return false; +} + +xcb_visualid_t QXcbSystemTrayTracker::netSystemTrayVisual() +{ if (m_trayWindow == XCB_WINDOW_NONE) - return false; + return XCB_NONE; xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL); @@ -174,7 +192,7 @@ bool QXcbSystemTrayTracker::visualHasAlphaChannel() false, m_trayWindow, tray_atom, XCB_ATOM_VISUALID, 0, 1); if (!systray_atom_reply) - return false; + return XCB_NONE; xcb_visualid_t systrayVisualId = XCB_NONE; if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply.get()) > 0) { @@ -182,12 +200,7 @@ bool QXcbSystemTrayTracker::visualHasAlphaChannel() systrayVisualId = vids[0]; } - if (systrayVisualId != XCB_NONE) { - quint8 depth = m_connection->primaryScreen()->depthOfVisual(systrayVisualId); - return depth == 32; - } - - return false; + return systrayVisualId; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h index a95b9374e9..c692cf590d 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -63,6 +63,7 @@ public: void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) override; + xcb_visualid_t visualId(); bool visualHasAlphaChannel(); signals: void systemTrayWindowChanged(QScreen *screen); @@ -73,6 +74,7 @@ private: xcb_atom_t selection); static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection); void emitSystemTrayWindowChanged(); + xcb_visualid_t netSystemTrayVisual(); const xcb_atom_t m_selection; const xcb_atom_t m_trayAtom; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d866ae025f..33395bdfdb 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -299,6 +299,7 @@ void QXcbWindow::create() destroy(); m_windowState = Qt::WindowNoState; + m_trayIconWindow = window()->objectName() == QLatin1String("QSystemTrayIconSysWindow"); Qt::WindowType type = window()->type(); @@ -356,7 +357,9 @@ void QXcbWindow::create() const xcb_visualtype_t *visual = nullptr; - if (connection()->hasDefaultVisualId()) { + if (m_trayIconWindow && connection()->systemTrayTracker()) { + visual = platformScreen->visualForId(connection()->systemTrayTracker()->visualId()); + } else if (connection()->hasDefaultVisualId()) { visual = platformScreen->visualForId(connection()->defaultVisualId()); if (!visual) qWarning() << "Failed to use requested visual id."; @@ -2669,11 +2672,6 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) case XEMBED_EMBEDDED_NOTIFY: xcb_map_window(xcb_connection(), m_window); xcbScreen()->windowShown(this); - // Without Qt::WA_TranslucentBackground, we use a ParentRelative BackPixmap. - // Clear the whole tray icon window to its background color as early as possible - // so that we can get a clean result from grabWindow() later. - xcb_clear_area(xcb_connection(), false, m_window, 0, 0, geometry().width(), geometry().height()); - xcb_flush(xcb_connection()); break; case XEMBED_FOCUS_IN: Qt::FocusReason reason; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 49968b2e0d..93526685cf 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -179,6 +179,8 @@ public: bool startSystemMoveResize(const QPoint &pos, int corner); bool doStartSystemMoveResize(const QPoint &globalPos, int corner); + bool isTrayIconWindow() const { return m_trayIconWindow; } + virtual void create(); virtual void destroy(); @@ -259,6 +261,7 @@ protected: bool m_embedded = false; bool m_alertState = false; bool m_minimized = false; + bool m_trayIconWindow = false; xcb_window_t m_netWmUserTimeWindow = XCB_NONE; QSurfaceFormat m_format; diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index df93e15f80..3f6166ae78 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -101,7 +101,6 @@ private: bool addToTray(); QSystemTrayIcon *q; - QPixmap background; }; QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) @@ -117,29 +116,7 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) const QSize size(22, 22); // Gnome, standard size setGeometry(QRect(QPoint(0, 0), size)); setMinimumSize(size); - - // We need two different behaviors depending on whether the X11 visual for the system tray - // (a) exists and (b) supports an alpha channel, i.e. is 32 bits. - // If we have a visual that has an alpha channel, we can paint this widget with a transparent - // background and it will work. - // However, if there's no alpha channel visual, in order for transparent tray icons to work, - // we do not have a transparent background on the widget, but set the BackPixmap property of our - // window to ParentRelative (so that it inherits the background of its X11 parent window), call - // xcb_clear_region before painting (so that the inherited background is visible) and then grab - // the just-drawn background from the X11 server. - bool hasAlphaChannel = QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannel(); - setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel); - if (!hasAlphaChannel) { - createWinId(); - QXcbWindowFunctions::setParentRelativeBackPixmap(windowHandle()); - - // XXX: This is actually required, but breaks things ("QWidget::paintEngine: Should no - // longer be called"). Why is this needed? When the widget is drawn, we use tricks to grab - // the tray icon's background from the server. If the tray icon isn't visible (because - // another window is on top of it), the trick fails and instead uses the content of that - // other window as the background. - // setAttribute(Qt::WA_PaintOnScreen); - } + setAttribute(Qt::WA_TranslucentBackground); addToTray(); } @@ -155,8 +132,6 @@ bool QSystemTrayIconSys::addToTray() if (!QXcbWindowFunctions::requestSystemTrayWindowDock(windowHandle())) return false; - if (!background.isNull()) - background = QPixmap(); show(); return true; } @@ -227,22 +202,6 @@ void QSystemTrayIconSys::paintEvent(QPaintEvent *) const QRect rect(QPoint(0, 0), geometry().size()); QPainter painter(this); - // If we have Qt::WA_TranslucentBackground set, during widget creation - // we detected the systray visual supported an alpha channel - if (testAttribute(Qt::WA_TranslucentBackground)) { - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(rect, Qt::transparent); - } else { - // clearRegion() was called on XEMBED_EMBEDDED_NOTIFY, so we hope that got done by now. - // Grab the tray background pixmap, before rendering the icon for the first time. - if (background.isNull()) { - background = QGuiApplication::primaryScreen()->grabWindow(winId(), - 0, 0, rect.size().width(), rect.size().height()); - } - // Then paint over the icon area with the background before compositing the icon on top. - painter.drawPixmap(QPoint(0, 0), background); - } - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); q->icon().paint(&painter, rect); } |