fix: 退出没有图标的应用AM崩溃
使用xcb ewmh的相关接口获取应用icon Log: 修复没有图标的应用退出时AM奔溃退出的问题 Influence: 任务栏应用图标正常显示
This commit is contained in:
parent
dc617910fb
commit
c043b392c7
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user