First, there is an buffer overflow bug in LinuxComponentPeer::setIcon(). This line
(in SVN) should be
(like it is in krakens initial post) otherwise you overflow the buffer.
Second…
[quote=“kraken”]yes, basically it tells the WM to use that specific ARGB icon for the use in a taskbar.
Your way was not understood by all window managers, and still it lacked the real implementation.[/quote]
Well, your way isn’t understood by all window managers either, at least my GNOME (Ubuntu Hardy) doesn’t display an window icon if it’s set as _NET_WM_ICON.
I implemented the other way to set an windows icon (the way Ptomaine suggested twice) and made some tests on my Ubuntu Hardy:
GNOME: _NET_WM_ICON fails, IconPixmapHint|IconMaskHint works
Xfce: _NET_WM_ICON works, IconPixmapHint|IconMaskHint works
KDE: _NET_WM_ICON works, IconPixmapHint|IconMaskHint works
So, IconPixmapHint|IconMaskHint is at least needed for GNOME.
I finally looked with xprop at the properties of some standard programs of GNOME, Xfce and KDE and all use both ways to set the icon.
Here is the code for them IconPixmapHint|IconMaskHint way to set the window icon (all in juce_linux_Windowing.cpp). First two functions to create pixmaps from images:
[code]Pixmap juce_createColourPixmapFromImage (Display* display, const Image& image)
{
const int width = image.getWidth();
const int height = image.getHeight();
const int size = width * height;
uint32* const colour = (uint32*) juce_malloc (size * sizeof (uint32));
int index = 0;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
colour[index++] = image.getPixelAt (x, y).getARGB();
XImage *ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap,
0, (char *) colour, width, height, 32, 0);
Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display),
width, height, 24);
GC gc = XCreateGC (display, pixmap, 0, 0);
XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height);
XFreeGC (display, gc);
juce_free (colour);
return pixmap;
}
Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& image)
{
const int width = image.getWidth();
const int height = image.getHeight();
const int stride = (width + 7) >> 3;
uint8* const mask = (uint8*) juce_calloc (stride * height);
bool msbfirst = (BitmapBitOrder (display) == MSBFirst);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
const uint8 bit = (uint8) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7)));
const int offset = y * stride + (x >> 3);
if (image.getPixelAt (x, y).getAlpha() >= 128)
mask[offset] |= bit;
}
}
Pixmap pixmap = XCreatePixmapFromBitmapData (display, DefaultRootWindow (display),
(char*) mask, width, height, 1, 0, 1);
juce_free (mask);
return pixmap;
}[/code]
Next the extended setIcon method in LinuxComponentPeer and the new deleteIconPixmaps method to free the pixmaps:
[code] void setIcon (const Image& newIcon)
{
const int width = newIcon.getWidth();
const int height = newIcon.getHeight();
const int dataSize = width * height + 2;
-
uint32* const data = (uint32*) juce_malloc (dataSize * sizeof (uint32));
int index = 0;
data[index++] = width;
data[index++] = height;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
data[index++] = newIcon.getPixelAt (x, y).getARGB();
XChangeProperty (display, windowH,
XInternAtom (display, "_NET_WM_ICON", False),
XA_CARDINAL, 32, PropModeReplace,
(unsigned char*) data, dataSize);
juce_free (data);
-
// update hints with the pixmaps
-
deleteIconPixmaps();
-
-
XWMHints *wmHints = XGetWMHints (display, windowH);
-
-
if (wmHints == 0)
-
wmHints = XAllocWMHints();
-
-
wmHints->flags |= IconPixmapHint | IconMaskHint;
-
wmHints->icon_pixmap = juce_createColourPixmapFromImage (display, newIcon);
-
wmHints->icon_mask = juce_createMaskPixmapFromImage (display, newIcon);
-
-
XSetWMHints (display, windowH, wmHints);
-
XFree (wmHints);
XSync (display, False);
}
-
void deleteIconPixmaps()
-
{
-
XWMHints *wmHints = XGetWMHints (display, windowH);
-
-
if (wmHints != 0)
-
{
-
if ((wmHints->flags & IconPixmapHint) != 0)
-
{
-
wmHints->flags &= ~IconPixmapHint;
-
XFreePixmap (display, wmHints->icon_pixmap);
-
}
-
-
if ((wmHints->flags & IconMaskHint) != 0)
-
{
-
wmHints->flags &= ~IconMaskHint;
-
XFreePixmap (display, wmHints->icon_mask);
-
}
-
-
XSetWMHints (display, windowH, wmHints);
-
XFree (wmHints);
-
}
-
}[/code]
Finally the modified destructor to call the new deleteIconPixmaps method:
[code] ~LinuxComponentPeer()
{
// it’s dangerous to delete a window on a thread other than the message thread…
checkMessageManagerIsLocked
deleteTaskBarIcon();