Xlib. Получить иконку приложения

157
28 декабря 2019, 10:30

Суть задачи в следующем: нужно получить иконку из окна приложения посредством xlib и поместить её в объект wxIcon (или wxImage или wxBitmap - не важно). Как мне удалось выяснить, есть два способа это сделать: используя свойство окна _NET_WM_ICON или через вызов XGetWMHints получить объект XWMHints, а из него достать icon_pixmap. Однако, со вторым методом проблемы возникли со старта: icon_pixmap определён как обычный unsigned long и как оттуда получить XPM-содержимое иконки я так и не нашел. Вот моя попытка реализовать первый вариант:

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

С его помощью, получается выцепить какую-то картинку, но она совсем не такая, как есть у приложения:

Первые три окна должны быть иконки терминала, примерно такие:

Но по факту получается что-то всоем не то. Вроде как, делал все в соответствии со спецификацией, но в итоге ерунда какая-то. Может кто подсказать, что не так в моей реализации или как получить XPM-содержимое иконки из icon_pixmap? Спасибо.

Answer 1

Если вдруг кто-нибудь еще столкнется с этой проблемой, то вот решение, которое сработало для меня. Идея в том, что бы из ARGB представления иконки самому собрать wxImage, ну и не стоит забывать, что _NET_WM_ICON возвращает содержимое в формате BGRA.

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);
}
READ ALSO
Как сделать переход из одного фрагмента в другой с помощью кнопки на экране?(без TabLayout)

Как сделать переход из одного фрагмента в другой с помощью кнопки на экране?(без TabLayout)

Как сделать переход из одного фрагмента в другой с помощью кнопки на экране?(без TabLayout)Если можно,буду благодарен за код

241
ImageTextButton как написать

ImageTextButton как написать

как создать ImageTextButton, в интернете гораздо меньше информации об этом, чем о простом ImageButton, есть у кого-то пример создания этой кнопочки с текстом?

144
Запуск jar файла двойным щелчком

Запуск jar файла двойным щелчком

Доброго времени суток

142
Не работает fetch Lazy для ManyToOne

Не работает fetch Lazy для ManyToOne

Имеется такая структура БД

125