Skip to content
Advertisement

How to set app icon for linux revisited and how does xfreerdp do it

I discovered that my appimag-ed application does not show any app icon in the window manager when launched, even though it has the icon inside itself. By the way, e.g., Obsidian app does suffer from this problem. In general, from searching on the Web, it looks like appimage fails with icons. Here e.g., a person also answers that appimage fails to provide app icons for a window manager: Electron Linux: .AppImage is not showing the icon, while .deb is. And also, when I load any app from https://appimage.github.io/apps/ — at least on Fedora 33 and 35 — I can see no app icons when launching them.

I tried to use workarounds like QMainWindow::setWindowIcon() or setting env variable XDG_DATA_DIRS, but it did not help — these approaches can be found on appimage-related sites.

I discovered answers on SO like by these links:

The idea of the answers is that you could not do such a thing and you have to install your .desktop file and icons to /usr/share via deb/rpm/etc. packages.

However, I discovered that it looks like xfreerdp carries its icon with it: I tried to change my system paths to icons (/usr/share/icons to /usr/share/icons_) temporarily and the xfreerdp’s icon was still there in the window manager, while those of other apps grayed out. Also, I searched for .svg or .png icons of xfreerdp on the whole os and have not found anything.

So I an just curious how they can do it? I looked into its source code on Github, but could not understand. It’s just an enigma for me really. Maybe, anybody has an idea how they do it or how this can be achieved at all?

Advertisement

Answer

Here is an incomplete answer, since it only cover the X11 case and does not describe how to translate from QT object to X11 handles. I don’t even know if this method will solve your specific problem.

The idea is to talk directly with X server to set the window icon, here, using the XCB API (same thing can be achieved using Xlib).

The X server need the bitmap data to be provided as 32 bit ARGB format, with two 32 bit unsigned integers ahead for image width and height. In a visual way, this what X server wait for:

 4 bytes   4 bytes   4 bytes   4 bytes   4 bytes
[ WIDTH  ][ HEIGHT ][  ARGB  ][  ARGB  ][  ARGB  ]...

Indeed, if you load image from common encoded image format like PNG, JPEG or other, you’ll need to properly decode image data to RGB(A), then convert bitmap to the proper ARGB format…

Here is the function to set the icon of any X windows. The first parameter c is the handle to the X server connection, the second w the handle/identifier (actually it is a simple integer) to X window. The third parameter icon_data is the icon data buffer as described above and the last parameter icon_size is the size, in bytes, of the buffer pointed by 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));
}

As you can see, the main purpose of this code is to modify/set a specific window property identified by _NET_WM_ICON. You’ll find some information about this X specific protocol and syntax here :

Notice that, I am not personally a great expert of X server protocols, I only digged some time ago this specific section for some low-level window management purpose.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement