?现象描述:
用户某软件在使用过程中发现部分应用子窗口显示在了任务栏窗口缩略图中。
窗口缩略图仅显示主窗口,不显示子窗口或弹出窗口等。
缩略图显示子窗口说明任务栏获取到的需要显示的窗口类型中有需要任务栏屏蔽的窗口类型,应获取到此窗口类型并进行屏蔽
利用xprop命令获取窗口类型,它是一个用于在X服务器中显示窗口属性的实用命令
xprop | grep TYPE
获取到需要屏蔽的窗口为Dialog,ComboBox,Utility类型的窗口.
任务栏需要在预览图中进行窗口屏蔽的操作
备注-xprop使用说明:
终端输入xprop并回车后,光标将变为十字光标,此时点击想要了解的窗口,就能获取该窗口的状态,类型等信息?
输出结果中的 _NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DIALOG, _KDE_NET_WM_WINDOW_TYPE_OVERRIDE, _NET_WM_WINDOW_TYPE_NORMAL 为我们想要了解的窗口的类型
也可直接通过xprop | grep TYPE命令直接获取窗口类型
任务栏处理预览图规则:
监听到桌面有窗口添加,执行onWindowAdded函数
??? connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &UKUITaskBar::onWindowAdded);
在onWindowAdded函数中进行判断,仅在acceptWindow(window)返回值为真的情况下进行预览图添加
void UKUITaskBar::onWindowAdded(WId window)
{
auto const pos = mKnownWindows.find(window);
if (mKnownWindows.end() == pos && acceptWindow(window))
addWindow(window);
}
在acceptWindow函数中对ignoreList中的窗口类型进行屏蔽
QFlags<NET::WindowTypeMask> ignoreList;
ignoreList新增:
ignoreList |= NET::DialogMask;
ignoreList |= NET::UtilityMask;
ignoreList |= NET::ComboBoxMask;
if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList)) return false;
/**
* @brief acceptWindow 对接收的窗口类型进行过滤
* @param window 窗口id
* @return 返回值为false代表不接受次窗口在任务栏预览图中显示
*/
bool UKUITaskBar::acceptWindow(WId window) const
{
QFlags<NET::WindowTypeMask> ignoreList;
ignoreList |= NET::DesktopMask;
ignoreList |= NET::DockMask;
ignoreList |= NET::SplashMask;
ignoreList |= NET::ToolbarMask;
ignoreList |= NET::MenuMask;
ignoreList |= NET::PopupMenuMask;
ignoreList |= NET::NotificationMask;
ignoreList |= NET::DialogMask;
ignoreList |= NET::UtilityMask;
ignoreList |= NET::ComboBoxMask;
KWindowInfo info(window, NET::WMWindowType | NET::WMState, NET::WM2TransientFor);
if (!info.valid())
return false;
if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList))
return false;
if (info.state() & NET::SkipTaskbar)
return false;
// WM_TRANSIENT_FOR hint not set - normal window
WId transFor = info.transientFor();
if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow())
return true;
info = KWindowInfo(transFor, NET::WMWindowType);
QFlags<NET::WindowTypeMask> normalFlag;
normalFlag |= NET::NormalMask;
normalFlag |= NET::DialogMask;
normalFlag |= NET::UtilityMask;
return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
}
备注-任务栏预览图核心代码:
QPixmap qimageFromXImage(XImage* ximage)
{
QImage::Format format = QImage::Format_ARGB32_Premultiplied;
if (ximage->depth == 24)
format = QImage::Format_RGB32;
else if (ximage->depth == 16)
format = QImage::Format_RGB16;
QImage image = QImage(reinterpret_cast<uchar*>(ximage->data),
ximage->width, ximage->height,
ximage->bytes_per_line, format).copy();
// 大端还是小端
if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && ximage->byte_order == MSBFirst)
|| (QSysInfo::ByteOrder == QSysInfo::BigEndian && ximage->byte_order == LSBFirst)) {
for (int i = 0; i < image.height(); i++) {
if (ximage->depth == 16) {
ushort* p = reinterpret_cast<ushort*>(image.scanLine(i));
ushort* end = p + image.width();
while (p < end) {
*p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
p++;
}
} else {
uint* p = reinterpret_cast<uint*>(image.scanLine(i));
uint* end = p + image.width();
while (p < end) {
*p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
| ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
p++;
}
}
}
}
// 修复alpha通道
if (format == QImage::Format_RGB32) {
QRgb* p = reinterpret_cast<QRgb*>(image.bits());
for (int y = 0; y < ximage->height; ++y) {
for (int x = 0; x < ximage->width; ++x)
p[x] |= 0xff000000;
p += ximage->bytes_per_line / 4;
}
}
return QPixmap::fromImage(image);
}