fix: 退出没有图标的应用AM崩溃
使用xcb ewmh的相关接口获取应用icon Log: 修复没有图标的应用退出时AM奔溃退出的问题 Influence: 任务栏应用图标正常显示
This commit is contained in:
parent
dc617910fb
commit
c043b392c7
@ -7,6 +7,7 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XRes.h>
|
||||
@ -421,41 +422,52 @@ std::string XCBUtils::getWMIconName(XWindow xid)
|
||||
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_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<BYTE> ret;
|
||||
// 根据宽高获取每个位置的数据,每行前有两个位置offset
|
||||
const auto size = 2 + it.width * it.height;
|
||||
std::vector<uint32_t> 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)
|
||||
|
@ -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<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;
|
||||
|
||||
typedef struct WindowFrameExtents {
|
||||
@ -202,7 +201,7 @@ public:
|
||||
std::string getWMIconName(XWindow xid);
|
||||
|
||||
// 获取窗口图标信息 _NET_WM_ICON
|
||||
std::vector<WMIcon> getWMIcon(XWindow xid);
|
||||
WMIcon getWMIcon(XWindow xid);
|
||||
|
||||
// WM_CLIENT_LEADER
|
||||
XWindow getWMClientLeader(XWindow xid);
|
||||
|
@ -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<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);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user