fix: 退出没有图标的应用AM崩溃

使用xcb ewmh的相关接口获取应用icon

Log: 修复没有图标的应用退出时AM奔溃退出的问题
Influence: 任务栏应用图标正常显示
This commit is contained in:
dengbo 2023-04-22 12:39:40 +08:00 committed by dengbo
parent dc617910fb
commit c043b392c7
3 changed files with 35 additions and 57 deletions

View File

@ -7,6 +7,7 @@
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <algorithm>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/XRes.h> #include <X11/extensions/XRes.h>
@ -421,41 +422,52 @@ std::string XCBUtils::getWMIconName(XWindow xid)
return ret; return ret;
} }
std::vector<WMIcon> XCBUtils::getWMIcon(XWindow xid) WMIcon XCBUtils::getWMIcon(XWindow xid)
{ {
std::vector<WMIcon> ret; WMIcon wmIcon{};
xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon(&m_ewmh, xid); xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon(&m_ewmh, xid);
xcb_ewmh_get_wm_icon_reply_t reply; xcb_ewmh_get_wm_icon_reply_t reply;
if (xcb_ewmh_get_wm_icon_reply(&m_ewmh, cookie, &reply, nullptr)) { xcb_generic_error_t *error;
xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply);
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) { auto fcn = [](xcb_ewmh_wm_icon_iterator_t it) {
std::vector<BYTE> ret; // 根据宽高获取每个位置的数据每行前有两个位置offset
const auto size = 2 + it.width * it.height;
std::vector<uint32_t> ret(size);
// data数据是按行从左至右从上至下排列 // data数据是按行从左至右从上至下排列
uint32_t *data = it.data; uint32_t *data = it.data;
if (!data) { if (!data) {
return ret; return ret;
} }
// 根据宽高获取每个位置的数据每行前有两个位置offset std::copy_n(data, size, ret.begin());
int area = it.width * it.height;
for (int i = 0; i < (2 + area) * 4; i++, data++) {
ret.push_back(*data);
}
return ret; return ret;
}; };
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);
// 获取不同size图标数据 xcb_ewmh_wm_icon_iterator_t wmIconIt{0, 0, nullptr};
while (iter.rem >= 1) { for (; iter.rem; xcb_ewmh_get_wm_icon_next(&iter)) {
xcb_ewmh_get_wm_icon_next(&iter); const int size = iter.width * iter.height;
ret.push_back({iter.width, iter.height, fcn(iter)}); 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 xcb_ewmh_get_wm_icon_reply_wipe(&reply); // clear
} }
return ret; return wmIcon;
} }
XWindow XCBUtils::getWMClientLeader(XWindow xid) XWindow XCBUtils::getWMClientLeader(XWindow xid)

View File

@ -44,11 +44,10 @@ typedef struct {
uint32_t status; uint32_t status;
} MotifWMHints; } MotifWMHints;
typedef unsigned char BYTE;
typedef struct { typedef struct {
uint32_t width; /** Icon width */ uint32_t width; /** Icon width */
uint32_t height; /** Icon height */ uint32_t height; /** Icon height */
std::vector<BYTE> data; /** Rows, left to right and top to bottom of the CARDINAL ARGB */ std::vector<uint32_t> data; /** Rows, left to right and top to bottom of the CARDINAL ARGB */
} WMIcon; } WMIcon;
typedef struct WindowFrameExtents { typedef struct WindowFrameExtents {
@ -202,7 +201,7 @@ public:
std::string getWMIconName(XWindow xid); std::string getWMIconName(XWindow xid);
// 获取窗口图标信息 _NET_WM_ICON // 获取窗口图标信息 _NET_WM_ICON
std::vector<WMIcon> getWMIcon(XWindow xid); WMIcon getWMIcon(XWindow xid);
// WM_CLIENT_LEADER // WM_CLIENT_LEADER
XWindow getWMClientLeader(XWindow xid); XWindow getWMClientLeader(XWindow xid);

View File

@ -359,47 +359,14 @@ void WindowInfoX::update()
QString WindowInfoX::getIconFromWindow() QString WindowInfoX::getIconFromWindow()
{ {
char *displayname = nullptr; WMIcon icon = XCB->getWMIcon(xid);
Display * dpy = XOpenDisplay (displayname);
if (!dpy) {
exit (1);
}
Atom net_wm_icon = XCB->getAtom("_NET_WM_ICON"); // invalid icon
if (icon.width == 0) {
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;
return QString(); 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; QImage img = QImage((uchar *)icon.data.data(), icon.width, icon.width, QImage::Format_ARGB32);
XGetWindowProperty(dpy, xid, net_wm_icon, 2, size, 0, AnyPropertyType, &type, &format, &nitems, &bytes,
&buf);
unsigned long *imgArr = (unsigned long *)(buf);
std::vector<uint32_t> 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);
QBuffer buffer; QBuffer buffer;
buffer.open(QIODevice::WriteOnly); buffer.open(QIODevice::WriteOnly);
img.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation); img.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);