@@ -282,37 +282,91 @@ void Util::setX11WindowInputShape(const xcb_window_t& window, const QSize& size)
282282 xcb_flush (m_x11connection);
283283}
284284
285+ uint8_t Util::getWindowVisualDepth (const xcb_window_t & window) const
286+ {
287+ auto attrCookie = xcb_get_window_attributes (m_x11connection, window);
288+ QSharedPointer<xcb_get_window_attributes_reply_t > attr (
289+ xcb_get_window_attributes_reply (m_x11connection, attrCookie, nullptr ),
290+ [](xcb_get_window_attributes_reply_t *ptr) { free (ptr); });
291+ if (!attr) {
292+ return 0 ;
293+ }
294+
295+ xcb_visualid_t visualId = attr->visual ;
296+ auto screen = xcb_setup_roots_iterator (xcb_get_setup (m_x11connection)).data ;
297+ xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator (screen);
298+ while (depthIter.rem ) {
299+ xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator (depthIter.data );
300+ while (visualIter.rem ) {
301+ if (visualIter.data ->visual_id == visualId) {
302+ return depthIter.data ->depth ;
303+ }
304+ xcb_visualtype_next (&visualIter);
305+ }
306+ xcb_depth_next (&depthIter);
307+ }
308+ return 0 ;
309+ }
310+
285311QImage Util::getX11WindowImageNonComposite (const xcb_window_t & window)
286312{
287313 QSize size = getX11WindowGeometry (window).size ();
288314 if (size.isEmpty ()) {
289315 return QImage ();
290316 }
291-
317+
292318 xcb_image_t *image = xcb_image_get (m_x11connection, window, 0 , 0 , size.width (), size.height (), 0xFFFFFFFF , XCB_IMAGE_FORMAT_Z_PIXMAP );
293319
294320 if (!image) {
295321 return QImage ();
296322 }
297323
298- QImage naiveConversion (image->data , image->width , image->height , QImage::Format_ARGB32);
324+ uint8_t visualDepth = getWindowVisualDepth (window);
325+ uint8_t imageDepth = image->depth ;
326+
327+ if (visualDepth != 32 ) {
328+ QImage result = convertFromNative (image, visualDepth);
329+ if (isTransparentImage (result)) {
330+ return QImage ();
331+ }
332+ return result;
333+ }
334+
335+ // X11 ARGB visual 的像素值是预乘 alpha 形式,使用 Format_ARGB32_Premultiplied
336+ // 才能与数据语义匹配,避免半透明像素显示偏亮。
337+ QImage naiveConversion (image->data , image->width , image->height , QImage::Format_ARGB32_Premultiplied);
299338 if (naiveConversion.isNull ()) {
300339 xcb_image_destroy (image);
301340 return QImage ();
302341 }
303342
304- if (isTransparentImage (naiveConversion)) {
305- QImage elaborateConversion = QImage (convertFromNative (image));
306- if (isTransparentImage (elaborateConversion)) {
307- return QImage ();
308- } else {
309- return elaborateConversion;
343+ QImage result = naiveConversion.copy ();
344+ xcb_image_destroy (image);
345+
346+ int w = result.width (), h = result.height ();
347+ int minA = 255 , maxA = 0 ;
348+ for (int x = 0 ; x < w; ++x)
349+ for (int y = 0 ; y < h; ++y) {
350+ int a = qAlpha (result.pixel (x, y));
351+ minA = qMin (minA, a);
352+ maxA = qMax (maxA, a);
310353 }
311- } else {
312- QImage res = naiveConversion.copy ();
313- xcb_image_destroy (image);
314- return res;
354+
355+ QRgb tl = result.pixel (0 , 0 );
356+
357+ if (maxA == 0 ) {
358+ return QImage ();
315359 }
360+
361+ if (minA == 255 ) {
362+ qCWarning (TRAYUTIL ) << " applying heuristic mask for all-opaque image" ;
363+ QImage m = result.createHeuristicMask ();
364+ QPixmap p = QPixmap::fromImage (std::move (result));
365+ p.setMask (QBitmap::fromImage (std::move (m)));
366+ result = p.toImage ();
367+ }
368+
369+ return result;
316370}
317371
318372bool Util::getX11WindowPixmapData (const xcb_window_t & window, QByteArray *data)
@@ -455,7 +509,7 @@ bool Util::isTransparentImage(const QImage &image)
455509 return true ;
456510}
457511
458- QImage Util::convertFromNative (xcb_image_t *xcbImage)
512+ QImage Util::convertFromNative (xcb_image_t *xcbImage, uint8_t visualDepth )
459513{
460514 QImage::Format format = QImage::Format_Invalid;
461515
@@ -498,7 +552,7 @@ QImage Util::convertFromNative(xcb_image_t *xcbImage)
498552 QImage deepCopy = image.copy ();
499553 xcb_image_destroy (xcbImage);
500554
501- if (format == QImage::Format_RGB32 && deepCopy.depth () == 32 ) {
555+ if (( format == QImage::Format_RGB32 || (format == QImage::Format_ARGB32_Premultiplied && visualDepth != 32 )) && deepCopy.depth () == 32 ) {
502556 QImage m = deepCopy.createHeuristicMask ();
503557 QPixmap p = QPixmap::fromImage (std::move (deepCopy));
504558 p.setMask (QBitmap::fromImage (std::move (m)));
0 commit comments