使用Xlib获取应用程序的图标?

时间:2019-03-29 08:34:57

标签: c++ wxwidgets xlib

我花了大约两天的时间才能达到目标,但是我没有做我需要做的事情。我的目标是从C ++应用程序的应用程序窗口中获取图标并将其保存到wxIcon(或wxImage或wxBitmap-无关紧要)对象中。 正如我在Internet上发现的,有两种方法可以检索图标:使用_NET_WM_ICON窗口属性和XGetWMHints(通过从XWMHints结构获取像素图)。

这是我尝试实现第一种方法的方式:

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);
}

但是我通过此代码获得的图标与应用程序具有的图标不同: Icons I get with this code

关于获取图标的第二种方式(从XGetWMHints结构获取像素图),我发现icon_pixmap字段定义为XID,即unsigned long,但我没有查找如何从此icon_pixmap获取XPM数据。

那么您能否解释一下我在代码中做错了什么,或者如何从XWMHints结构的“ icon_pixmap”字段获取图标? 谢谢。

1 个答案:

答案 0 :(得分:0)

以防万一其他人需要解决方案:

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);
}

这个想法只是从“原始”数据创建wxImage。在x64 Ubuntu 16.04上可以运行