I spent for about two days to reach the goal, however I didn't manage to do what I needed. My goal is to get the icon from application's window in my C++ application and save it into wxIcon (or wxImage or wxBitmap - doesn't matter) object.
As I found in Internet there are two variants to do retrieve the icon: using _NET_WM_ICON
window property and using XGetWMHints
(by getting pixmap from XWMHints
structure).
This is how I tried to implement first approach:
void ApplicationHelper::GetIcon(SRunningWindow* pDesc, void* pDisplay,
TWindow iWindow, unsigned long uiIconAtom)
{
unsigned long nitems, bytesafter;
unsigned char *ret;
int format;
Atom type;
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 0, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
int width = *(int*)ret;
XFree(ret);
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 1, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
int height = *(int*)ret;
XFree(ret);
int size = width * height;
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 2, size, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
unsigned char* imgData = new unsigned char[width * height * 3]; // RGB data
unsigned char* alphaData = new unsigned char[width * height]; // alpha chanel
int offset = sizeof(long) == 8 ? 8 : 4; // for 64bit systems data represented in order: blue, green, red, alpha, followed by 4 zeros
int imgIdx = 0;
int alphaIdx = 0;
for (int i=0; i < nitems; i += offset)
{
imgData[imgIdx] = ret[i + 2]; // R
imgData[imgIdx + 1] = ret[i + 1]; // G
imgData[imgIdx + 2] = ret[i]; // B
alphaData[alphaIdx++] = ret[i + 3]; // A
imgIdx += 3;
}
XFree(ret);
wxImage img(width, height, imgData, alphaData);
img.Rescale(16, 16);
wxBitmap bmp(img);
pDesc->icon.CopyFromBitmap(bmp);
}
But icons I get with this code are not the same as the applications have:
Regarding second variant of getting icons (getting pixmap from XGetWMHints
structure) I found, that icon_pixmap
field is defined as XID
which is unsigned long
and I didn't find how to get XPM data from this icon_pixmap
.
So could you please explain what I did wrong in my code or how to get icon from 'icon_pixmap' field of XWMHints
structure?
Thanks.
Just in case if someone else will need the solution:
void ApplicationHelper::GetIcon(SRunningWindow* pDesc, void* pDisplay, TWindow iWindow, unsigned long uiIconAtom)
{
unsigned long nitems, bytesafter;
unsigned char *ret;
int format;
Atom type;
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 0, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
int width = *(int*)ret;
XFree(ret);
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 1, 1, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
int height = *(int*)ret;
XFree(ret);
int size = width * height;
XGetWindowProperty((Display*) pDisplay, iWindow, uiIconAtom, 2, size, 0, AnyPropertyType, &type, &format, &nitems, &bytesafter, &ret);
unsigned int* imgData = new unsigned int[size];
unsigned long* ul = (unsigned long*)ret;
for (int i=0; i < nitems; ++i)
{
imgData[i] = (unsigned int)ul[i];
}
XFree(ret);
wxImage img(width, height);
img.InitAlpha();
unsigned char* argb = (unsigned char*)imgData;
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
unsigned char a = argb[3];
unsigned char r = argb[2] * a / 255;
unsigned char g = argb[1] * a / 255;
unsigned char b = argb[0] * a / 255;
img.SetRGB(x, y, r, g, b);
img.SetAlpha(x, y, a);
argb += 4;
}
}
img.Rescale(32, 32);
wxBitmap bmp(img);
delete[]imgData;
pDesc->icon.CopyFromBitmap(bmp);
}
The idea is just to create wxImage from "raw" data. On x64 Ubuntu 16.04 it works