Skip to content

Commit

Permalink
Slight rework and add debug around reading the application icon
Browse files Browse the repository at this point in the history
  • Loading branch information
user-none committed Sep 24, 2024
1 parent d8aa4d3 commit 533a127
Showing 1 changed file with 72 additions and 57 deletions.
129 changes: 72 additions & 57 deletions src/xlibutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,9 +677,10 @@ static QImage imageFromX11IconData(unsigned long *iconData, unsigned long dataLe
return iconImage.copy();
}

static QImage imageFromX11Pixmap(Display *display, Pixmap pixmap, int width, int height)
static QImage imageFromX11Pixmap(Display *display, Pixmap pixmap, int x, int y, unsigned int width, unsigned int height)
{
XImage *ximage = XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
qDebug() << "x, y = " << x << y;
XImage *ximage = XGetImage(display, pixmap, x, y, width, height, AllPlanes, ZPixmap);
if (!ximage)
return QImage();

Expand All @@ -690,73 +691,87 @@ static QImage imageFromX11Pixmap(Display *display, Pixmap pixmap, int width, int
return result;
}

QPixmap XLibUtil::getWindowIcon(windowid_t window)
static QPixmap getWindowIconNetWMIcon(windowid_t window)
{
if (!window)
return QPixmap();

qDebug() << __func__;
QPixmap appIcon;
Display *display = getDisplay();
static Atom netWmIcon = XInternAtom(display, "_NET_WM_ICON", false);
Atom actualType;
int actualFormat;
unsigned long nItems, bytesAfter;
unsigned char *data = nullptr;

if (XGetWindowProperty(display, window, netWmIcon, 0, LONG_MAX, false, XA_CARDINAL, &actualType, &actualFormat,
&nItems, &bytesAfter, &data) != Success || data == NULL)
return appIcon;

qDebug() << "icon format" << actualFormat;
if (actualFormat != 32)
return appIcon;

unsigned long *iconData = reinterpret_cast<unsigned long *>(data);
unsigned long dataLength = nItems;

// Extract the largest icon available
QImage largestImage;
unsigned long maxIconSize = 0;

for (unsigned long i = 0; i < dataLength;) {
unsigned long width = iconData[i];
unsigned long height = iconData[i + 1];
unsigned long iconSize = width * height;

if (iconSize > maxIconSize) {
largestImage = imageFromX11IconData(&iconData[i], dataLength - i);
maxIconSize = iconSize;
}

i += (2 + iconSize);
}

if (!largestImage.isNull())
appIcon = QPixmap::fromImage(largestImage);

XFree(data);
return appIcon;
}

static QPixmap getWindowIconWMHints(windowid_t window)
{
qDebug() << __func__;
QPixmap appIcon;
Display *display = getDisplay();

// First try to get the icon from WM_HINTS
XWMHints *wm_hints = XGetWMHints(display, window);
if (wm_hints != nullptr) {
if (!(wm_hints->flags & IconMaskHint)) {
wm_hints->icon_mask = 0;
}

if ((wm_hints->flags & IconPixmapHint) && (wm_hints->icon_pixmap)) {
Window root;
int x, y;
unsigned int width, height, border_width, depth;
XGetGeometry(display, wm_hints->icon_pixmap, &root, &x, &y, &width, &height, &border_width, &depth);
if (wm_hints == nullptr)
return appIcon;

QImage image = imageFromX11Pixmap(display, wm_hints->icon_pixmap, width, height);
appIcon = QPixmap::fromImage(image);
}
if (wm_hints->icon_pixmap) {
Window root;
int x = 0, y = 0;
unsigned int width = 0, height = 0, border_width, depth;
XGetGeometry(display, wm_hints->icon_pixmap, &root, &x, &y, &width, &height, &border_width, &depth);

XFree(wm_hints);
QImage image = imageFromX11Pixmap(display, wm_hints->icon_pixmap, x, y, width, height);
appIcon = QPixmap::fromImage(image);
}

// Fallback to _NET_WM_ICON if WM_HINTS icon is not available
if (appIcon.isNull()) {
static Atom netWmIcon = XInternAtom(display, "_NET_WM_ICON", false);
Atom actualType;
int actualFormat;
unsigned long nItems, bytesAfter;
unsigned char *data = nullptr;

if (XGetWindowProperty(display, window, netWmIcon, 0, LONG_MAX, false, XA_CARDINAL, &actualType, &actualFormat,
&nItems, &bytesAfter, &data) == Success &&
data)
{
unsigned long *iconData = reinterpret_cast<unsigned long *>(data);
unsigned long dataLength = nItems;

// Extract the largest icon available
QImage largestImage;
unsigned long maxIconSize = 0;

for (unsigned long i = 0; i < dataLength;) {
unsigned long width = iconData[i];
unsigned long height = iconData[i + 1];
unsigned long iconSize = width * height;

if (iconSize > maxIconSize) {
largestImage = imageFromX11IconData(&iconData[i], dataLength - i);
maxIconSize = iconSize;
}
XFree(wm_hints);
return appIcon;
}

i += (2 + iconSize);
}
QPixmap XLibUtil::getWindowIcon(windowid_t window)
{
if (!window)
return QPixmap();

if (!largestImage.isNull()) {
appIcon = QPixmap::fromImage(largestImage);
}
// First try _NET_WM_ICON
QPixmap appIcon = getWindowIconNetWMIcon(window);

XFree(data);
}
}
// Fallback to WM_HINTS if _NET_WM_ICON wasn't set
if (appIcon.isNull())
appIcon = getWindowIconWMHints(window);

return appIcon;
}
Expand Down

0 comments on commit 533a127

Please sign in to comment.