From c043b392c70179bdbbaf7a1d61eb744a7e59d2da Mon Sep 17 00:00:00 2001 From: dengbo Date: Sat, 22 Apr 2023 12:39:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=80=80=E5=87=BA=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E7=9A=84=E5=BA=94=E7=94=A8AM=E5=B4=A9?= =?UTF-8?q?=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用xcb ewmh的相关接口获取应用icon Log: 修复没有图标的应用退出时AM奔溃退出的问题 Influence: 任务栏应用图标正常显示 --- src/lib/xcbutils.cpp | 46 ++++++++++++++++++++------------ src/lib/xcbutils.h | 5 ++-- src/modules/dock/windowinfox.cpp | 41 +++------------------------- 3 files changed, 35 insertions(+), 57 deletions(-) diff --git a/src/lib/xcbutils.cpp b/src/lib/xcbutils.cpp index b52b967..f617750 100644 --- a/src/lib/xcbutils.cpp +++ b/src/lib/xcbutils.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -421,41 +422,52 @@ std::string XCBUtils::getWMIconName(XWindow xid) return ret; } -std::vector XCBUtils::getWMIcon(XWindow xid) +WMIcon XCBUtils::getWMIcon(XWindow xid) { - std::vector ret; + WMIcon wmIcon{}; xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon(&m_ewmh, xid); xcb_ewmh_get_wm_icon_reply_t reply; - if (xcb_ewmh_get_wm_icon_reply(&m_ewmh, cookie, &reply, nullptr)) { - xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply); + xcb_generic_error_t *error; + + auto ret = xcb_ewmh_get_wm_icon_reply(&m_ewmh, cookie, &reply, &error); + + if (error) { + std::cout << "failed to get wm icon" << error->error_code; + std::free(error); + return wmIcon; + } + + if (ret) { auto fcn = [](xcb_ewmh_wm_icon_iterator_t it) { - std::vector ret; + // 根据宽高获取每个位置的数据,每行前有两个位置offset + const auto size = 2 + it.width * it.height; + std::vector ret(size); // data数据是按行从左至右,从上至下排列 uint32_t *data = it.data; if (!data) { return ret; } - // 根据宽高获取每个位置的数据,每行前有两个位置offset - int area = it.width * it.height; - for (int i = 0; i < (2 + area) * 4; i++, data++) { - ret.push_back(*data); - } + std::copy_n(data, size, ret.begin()); return ret; }; - ret.push_back({iter.width, iter.height, fcn(iter)}); - - // 获取不同size图标数据 - while (iter.rem >= 1) { - xcb_ewmh_get_wm_icon_next(&iter); - ret.push_back({iter.width, iter.height, fcn(iter)}); + // 获取icon中size最大的图标 + xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply); + xcb_ewmh_wm_icon_iterator_t wmIconIt{0, 0, nullptr}; + for (; iter.rem; xcb_ewmh_get_wm_icon_next(&iter)) { + const int size = iter.width * iter.height; + if (size > 0 && size > wmIconIt.width * wmIconIt.height) { + wmIconIt = iter; + } } + wmIcon = WMIcon{wmIconIt.width, wmIconIt.height, fcn(wmIconIt)}; + xcb_ewmh_get_wm_icon_reply_wipe(&reply); // clear } - return ret; + return wmIcon; } XWindow XCBUtils::getWMClientLeader(XWindow xid) diff --git a/src/lib/xcbutils.h b/src/lib/xcbutils.h index f117551..f069dc3 100644 --- a/src/lib/xcbutils.h +++ b/src/lib/xcbutils.h @@ -44,11 +44,10 @@ typedef struct { uint32_t status; } MotifWMHints; -typedef unsigned char BYTE; typedef struct { uint32_t width; /** Icon width */ uint32_t height; /** Icon height */ - std::vector data; /** Rows, left to right and top to bottom of the CARDINAL ARGB */ + std::vector data; /** Rows, left to right and top to bottom of the CARDINAL ARGB */ } WMIcon; typedef struct WindowFrameExtents { @@ -202,7 +201,7 @@ public: std::string getWMIconName(XWindow xid); // 获取窗口图标信息 _NET_WM_ICON - std::vector getWMIcon(XWindow xid); + WMIcon getWMIcon(XWindow xid); // WM_CLIENT_LEADER XWindow getWMClientLeader(XWindow xid); diff --git a/src/modules/dock/windowinfox.cpp b/src/modules/dock/windowinfox.cpp index cbbee80..be4ab5c 100644 --- a/src/modules/dock/windowinfox.cpp +++ b/src/modules/dock/windowinfox.cpp @@ -359,47 +359,14 @@ void WindowInfoX::update() QString WindowInfoX::getIconFromWindow() { - char *displayname = nullptr; - Display * dpy = XOpenDisplay (displayname); - if (!dpy) { - exit (1); - } + WMIcon icon = XCB->getWMIcon(xid); - Atom net_wm_icon = XCB->getAtom("_NET_WM_ICON"); - - unsigned char *buf = nullptr; - int format; - Atom type; - unsigned long nitems, bytes; - - // Get image size - XGetWindowProperty(dpy, xid, net_wm_icon, 0, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &buf); - if (!buf) { - qWarning() << "Failed to get width for window icon, window id:" << xid; + // invalid icon + if (icon.width == 0) { return QString(); } - int width = *(int *)buf; - XFree(buf); - XGetWindowProperty(dpy, xid, net_wm_icon, 1, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &buf); - if (!buf) { - qWarning() << "Failed to get height for window icon, window id:" << xid; - return QString(); - } - int height = *(int *)buf; - XFree(buf); - long size = width * height; - XGetWindowProperty(dpy, xid, net_wm_icon, 2, size, 0, AnyPropertyType, &type, &format, &nitems, &bytes, - &buf); - unsigned long *imgArr = (unsigned long *)(buf); - std::vector imgARGB32(size); - for (long i = 0; i < size; ++i) { - imgARGB32[i] = (uint32_t)(imgArr[i]); - } - - XFree(buf); - - QImage img = QImage((uchar *)imgARGB32.data(), width, height, QImage::Format_ARGB32); + QImage img = QImage((uchar *)icon.data.data(), icon.width, icon.width, QImage::Format_ARGB32); QBuffer buffer; buffer.open(QIODevice::WriteOnly); img.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);