如何为 linux 重新设置应用程序图标以及 xfreerdp 是如何做到的
How to set app icon for linux revisited and how does xfreerdp do it
我发现我的 appimag 应用程序启动时在 window 管理器中不显示任何应用程序图标,即使它本身有图标。顺便说一句,例如,Obsidian 应用程序确实遇到了这个问题。一般来说,从网络上搜索,它看起来像 appimage 图标失败。例如,有人回答说 appimage 无法为 window 管理器提供应用程序图标:Electron Linux: .AppImage is not showing the icon, while .deb is. And also, when I load any app from https://appimage.github.io/apps/——至少在 Fedora 33 和 35 上——启动它们时我看不到应用程序图标。
我尝试使用 QMainWindow::setWindowIcon()
或设置环境变量 XDG_DATA_DIRS
等变通方法,但没有用——这些方法可以在与 appimage 相关的网站上找到。
我通过这些链接找到了关于 SO 的答案:
- Qt Creator - how to set application icon for ubuntu linux?
- How do I give a C++ program an icon?
答案的想法是你不能做这样的事情,你必须通过 deb/rpm/etc 安装你的 .desktop
文件和图标到 /usr/share
。包。
然而,我发现它看起来像 xfreerdp 带有它的图标:我试图暂时将我的系统路径更改为图标(/usr/share/icons
到 /usr/share/icons_
)并且 xfreerdp 的图标仍然存在在 window 管理器中,而其他应用程序 ose 显示为灰色。此外,我搜索了整个 xfreerdp 的 .svg 或 .png 图标os,但没有找到任何东西。
所以我很好奇他们是怎么做到的?我在 Github 上查看了它的源代码,但无法理解。这对我来说真的是个谜。也许,任何人都知道他们是如何做到的或如何实现的?
这是一个不完整的答案,因为它只涵盖了 X11 的情况,没有描述如何从 QT 对象转换为 X11 句柄。 我什至不知道这个方法是否能解决你的具体问题。
想法是直接与 X 服务器对话以设置 window 图标,这里使用 XCB API(使用 Xlib 也可以实现同样的事情)。
X server 需要提供32位ARGB格式的位图数据,图像的宽和高前面有两个32位无符号整数。以直观的方式,这是 X 服务器等待的内容:
4 bytes 4 bytes 4 bytes 4 bytes 4 bytes
[ WIDTH ][ HEIGHT ][ ARGB ][ ARGB ][ ARGB ]...
事实上,如果您从常见的编码图像格式(如 PNG、JPEG 或其他格式)加载图像,您需要将图像数据正确解码为 RGB(A),然后将位图转换为正确的 ARGB 格式...
这里是设置任意X图标的函数windows。第一个参数c
是到X服务器连接的句柄,第二个w
是handle/identifier(实际上是一个简单的整数)到Xwindow。第三个参数 icon_data
是如上所述的图标数据缓冲区,最后一个参数 icon_size
是 icon_data
.
指向的缓冲区的大小,以字节为单位
setWindowIcon(xcb_connection_t* c, xcb_window_t w, uint32_t* icon_data, size_t icon_size)
{
// get the _NET_WM_ICON atom
xcb_intern_atom_reply_t* r;
r = xcb_intern_atom_reply(c, xcb_intern_atom(c,1,12,"_NET_WM_ICON"), 0);
xcb_atom_t _NET_WM_ICON = r->atom;
free(r);
// get the CARDINAL atom
r = xcb_intern_atom_reply(c, xcb_intern_atom(c,1,8,"CARDINAL"), 0);
xcb_atom_t CARDINAL = r->atom;
free(r);
// change window property
xcb_change_property(c, XCB_PROP_MODE_REPLACE, w, _NET_WM_ICON, CARDINAL, 32, icon_size, icon_data);
// make sure everything is done
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
}
如您所见,这段代码的主要目的是modify/set一个由_NET_WM_ICON
识别的特定window属性。您将在此处找到有关此 X 特定协议和语法的一些信息:
- https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html
- https://tronche.com/gui/x/xlib/window-information/properties-and-atoms.html
请注意,我个人并不是 X 服务器协议的专家,我只是在一段时间前挖掘了这个特定部分用于某些 low-level window 管理目的。
我发现我的 appimag 应用程序启动时在 window 管理器中不显示任何应用程序图标,即使它本身有图标。顺便说一句,例如,Obsidian 应用程序确实遇到了这个问题。一般来说,从网络上搜索,它看起来像 appimage 图标失败。例如,有人回答说 appimage 无法为 window 管理器提供应用程序图标:Electron Linux: .AppImage is not showing the icon, while .deb is. And also, when I load any app from https://appimage.github.io/apps/——至少在 Fedora 33 和 35 上——启动它们时我看不到应用程序图标。
我尝试使用 QMainWindow::setWindowIcon()
或设置环境变量 XDG_DATA_DIRS
等变通方法,但没有用——这些方法可以在与 appimage 相关的网站上找到。
我通过这些链接找到了关于 SO 的答案:
- Qt Creator - how to set application icon for ubuntu linux?
- How do I give a C++ program an icon?
答案的想法是你不能做这样的事情,你必须通过 deb/rpm/etc 安装你的 .desktop
文件和图标到 /usr/share
。包。
然而,我发现它看起来像 xfreerdp 带有它的图标:我试图暂时将我的系统路径更改为图标(/usr/share/icons
到 /usr/share/icons_
)并且 xfreerdp 的图标仍然存在在 window 管理器中,而其他应用程序 ose 显示为灰色。此外,我搜索了整个 xfreerdp 的 .svg 或 .png 图标os,但没有找到任何东西。
所以我很好奇他们是怎么做到的?我在 Github 上查看了它的源代码,但无法理解。这对我来说真的是个谜。也许,任何人都知道他们是如何做到的或如何实现的?
这是一个不完整的答案,因为它只涵盖了 X11 的情况,没有描述如何从 QT 对象转换为 X11 句柄。 我什至不知道这个方法是否能解决你的具体问题。
想法是直接与 X 服务器对话以设置 window 图标,这里使用 XCB API(使用 Xlib 也可以实现同样的事情)。
X server 需要提供32位ARGB格式的位图数据,图像的宽和高前面有两个32位无符号整数。以直观的方式,这是 X 服务器等待的内容:
4 bytes 4 bytes 4 bytes 4 bytes 4 bytes
[ WIDTH ][ HEIGHT ][ ARGB ][ ARGB ][ ARGB ]...
事实上,如果您从常见的编码图像格式(如 PNG、JPEG 或其他格式)加载图像,您需要将图像数据正确解码为 RGB(A),然后将位图转换为正确的 ARGB 格式...
这里是设置任意X图标的函数windows。第一个参数c
是到X服务器连接的句柄,第二个w
是handle/identifier(实际上是一个简单的整数)到Xwindow。第三个参数 icon_data
是如上所述的图标数据缓冲区,最后一个参数 icon_size
是 icon_data
.
setWindowIcon(xcb_connection_t* c, xcb_window_t w, uint32_t* icon_data, size_t icon_size)
{
// get the _NET_WM_ICON atom
xcb_intern_atom_reply_t* r;
r = xcb_intern_atom_reply(c, xcb_intern_atom(c,1,12,"_NET_WM_ICON"), 0);
xcb_atom_t _NET_WM_ICON = r->atom;
free(r);
// get the CARDINAL atom
r = xcb_intern_atom_reply(c, xcb_intern_atom(c,1,8,"CARDINAL"), 0);
xcb_atom_t CARDINAL = r->atom;
free(r);
// change window property
xcb_change_property(c, XCB_PROP_MODE_REPLACE, w, _NET_WM_ICON, CARDINAL, 32, icon_size, icon_data);
// make sure everything is done
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
}
如您所见,这段代码的主要目的是modify/set一个由_NET_WM_ICON
识别的特定window属性。您将在此处找到有关此 X 特定协议和语法的一些信息:
- https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html
- https://tronche.com/gui/x/xlib/window-information/properties-and-atoms.html
请注意,我个人并不是 X 服务器协议的专家,我只是在一段时间前挖掘了这个特定部分用于某些 low-level window 管理目的。