all repos — fluxbox @ 46fdf4d1b4043588b057fcc9a03f5f66b6b09354

custom fork of the fluxbox windowmanager

use _NET_WM_ICON property as resource for icons, fixed partly #1852693

instead of depending on proper icons in the old icccm wmhints, fluxbox now
tries to get the icon data stored in _NET_WM_ICON
Mathias Gumz akira at fluxbox dot org
commit

46fdf4d1b4043588b057fcc9a03f5f66b6b09354

parent

611b6aa57e34ed8e52cb6b88c9adbafe4d67c6e2

3 files changed, 180 insertions(+), 11 deletions(-)

jump to
M src/Ewmh.ccsrc/Ewmh.cc

@@ -35,7 +35,9 @@ #include "FbTk/FbWindow.hh"

#include "FbTk/I18n.hh" #include "FbTk/XLayerItem.hh" #include "FbTk/XLayer.hh" +#include "FbTk/FbPixmap.hh" +#include <X11/Xproto.h> #include <X11/Xatom.h> #include <iostream> #include <algorithm>

@@ -59,6 +61,149 @@ #define FB_new_nothrow new(std::nothrow)

#endif +namespace { + +/* From Extended Window Manager Hints, draft 1.3: + * + * _NET_WM_ICON CARDINAL[][2+n]/32 + * + * This is an array of possible icons for the client. This specification does + * not stipulate what size these icons should be, but individual desktop + * environments or toolkits may do so. The Window Manager MAY scale any of + * these icons to an appropriate size. + * + * This is an array of 32bit packed CARDINAL ARGB with high byte being A, low + * byte being B. The first two cardinals are width, height. Data is in rows, + * left to right and top to bottom. + */ +void extractNetWmIcon(Atom net_wm_icon, WinClient& winclient) { + + typedef std::pair<int, int> Size; + typedef std::map<Size, const unsigned long*> IconContainer; + + // attention: the returned data for XA_CARDINAL is long if the rfmt equals + // 32. sizeof(long) on 64bit machines is 8. + unsigned long* raw_data = 0; + long nr_icon_data = 0; + + { + Atom rtype; + int rfmt; + unsigned long nr_read; + unsigned long nr_bytes_left; + + // no data or no _NET_WM_ICON + if (! winclient.property(net_wm_icon, 0L, 0L, False, XA_CARDINAL, + &rtype, &rfmt, &nr_read, &nr_bytes_left, + reinterpret_cast<unsigned char**>(&raw_data)) || nr_bytes_left == 0) { + + if (raw_data) + XFree(raw_data); + + return; + } + + // actually there is some data in _NET_WM_ICON + nr_icon_data = nr_bytes_left / sizeof(CARD32); + + // read all the icons stored in _NET_WM_ICON + winclient.property(net_wm_icon, 0L, nr_icon_data, False, XA_CARDINAL, + &rtype, &rfmt, &nr_read, &nr_bytes_left, + reinterpret_cast<unsigned char**>(&raw_data)); + } + + IconContainer icon_data; // stores all available data, sorted by size (width x height) + int width; + int height; + + // analyze the available icons + long i; + for (i = 0; i < nr_icon_data; i += width * height ) { + + width = raw_data[i++]; + height = raw_data[i++]; + + icon_data[Size(width, height)] = &raw_data[i]; + } + + Display* dpy = FbTk::App::instance()->display(); + int scrn = winclient.screen().screenNumber(); + + // pick the smallest icon size atm + // TODO: find a better criteria + width = icon_data.begin()->first.first; + height = icon_data.begin()->first.second; + + // tmp image for the pixmap + XImage* img_pm = XCreateImage(dpy, DefaultVisual(dpy, scrn), winclient.depth(), + ZPixmap, + 0, NULL, width, height, 32, 0); + if (!img_pm) { + XFree(raw_data); + return; + } + + // tmp image for the mask + XImage* img_mask = XCreateImage(dpy, DefaultVisual(dpy, scrn), 1, + XYBitmap, + 0, NULL, width, height, 32, 0); + + if (!img_mask) { + XFree(raw_data); + XDestroyImage(img_pm); + return; + } + + // allocate some memory for the icons at client side + img_pm->data = new char[img_pm->bytes_per_line * height]; + img_mask->data = new char[img_mask->bytes_per_line * height]; + + + const unsigned long* src = icon_data.begin()->second; + unsigned int pixel; + int x; + int y; + unsigned char r, g, b, a; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++, src++) { + + pixel = *src; // use only 32bit + + a = ( pixel & 0xff000000 ) >> 24; + r = ( pixel & 0x00ff0000 ) >> 16; + g = ( pixel & 0x0000ff00 ) >> 8; + b = ( pixel & 0x000000ff ); + + // transfer color data + XPutPixel(img_pm, x, y, pixel & 0x00ffffff ); // TODO: this only works in 24bit depth + + // transfer mask data + XPutPixel(img_mask, x, y, a > 127 ? 0 : 1); + } + } + + // the final icon + FbTk::PixmapWithMask icon; + icon.pixmap() = FbTk::FbPixmap(winclient.drawable(), width, height, winclient.depth()); + icon.mask() = FbTk::FbPixmap(winclient.drawable(), width, height, 1); + + FbTk::GContext gc_pm(icon.pixmap()); + FbTk::GContext gc_mask(icon.mask()); + + XPutImage(dpy, icon.pixmap().drawable(), gc_pm.gc(), img_pm, 0, 0, 0, 0, width, height); + XPutImage(dpy, icon.mask().drawable(), gc_mask.gc(), img_mask, 0, 0, 0, 0, width, height); + + XDestroyImage(img_pm); // also frees img_pm->data + XDestroyImage(img_mask); // also frees img_mask->data + + XFree(raw_data); + + winclient.setIcon(icon); +} + +}; // end anonymous namespace + class Ewmh::EwmhAtoms { public:

@@ -284,6 +429,7 @@ // window properties

m_net->wm_strut, m_net->wm_state, m_net->wm_name, + m_net->wm_icon, m_net->wm_icon_name, // states that we support:

@@ -386,7 +532,11 @@

Atom ret_type; int fmt; unsigned long nitems, bytes_after; - unsigned char *data = 0; + unsigned char* data = 0; + + + extractNetWmIcon(m_net->wm_icon, winclient); + /* From Extended Window Manager Hints, draft 1.3: *

@@ -1051,6 +1201,9 @@ winclient.fbwindow()->titleSig().notify();

return true; } else if (the_property == m_net->wm_icon_name) { // we don't use icon title, since we don't show icons + return true; + } else if (the_property == m_net->wm_icon) { + extractNetWmIcon(m_net->wm_icon, winclient); return true; }
M src/WinClient.ccsrc/WinClient.cc

@@ -358,9 +358,17 @@ m_title = string(Xutil::getWMName(window()), 0, 512);

titleSig().notify(); } -void WinClient::setTitle(FbTk::FbString &title) { +void WinClient::setTitle(const FbTk::FbString &title) { m_title = title; m_title_override = true; + titleSig().notify(); +} + +void WinClient::setIcon(const FbTk::PixmapWithMask& pm) { + + m_icon.pixmap().copy(pm.pixmap()); + m_icon.mask().copy(pm.mask()); + m_icon_override = true; titleSig().notify(); }

@@ -429,15 +437,18 @@

if (wmhint->flags & WindowGroupHint && !window_group) window_group = wmhint->window_group; - if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) - m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0); - else - m_icon.pixmap().release(); + if (! m_icon_override) { + + if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) + m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0); + else + m_icon.pixmap().release(); - if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) - m_icon.mask().copy(wmhint->icon_mask, 0, 0); - else - m_icon.mask().release(); + if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) + m_icon.mask().copy(wmhint->icon_mask, 0, 0); + else + m_icon.mask().release(); + } if (fbwindow()) { if (wmhint->flags & XUrgencyHint) {
M src/WinClient.hhsrc/WinClient.hh

@@ -59,11 +59,15 @@ void updateWMClassHint();

void updateWMProtocols(); // override the title with this - void setTitle(FbTk::FbString &title); + void setTitle(const FbTk::FbString &title); void updateTitle(); /// updates transient window information void updateTransientInfo(); + // override the icon with this + void setIcon(const FbTk::PixmapWithMask& pm); + + // update some thints void updateMWMHints(); void updateWMHints(); void updateWMNormalHints();

@@ -164,6 +168,7 @@

int m_win_gravity; bool m_title_override; + bool m_icon_override; Focusable::WindowType m_window_type; MwmHints *m_mwm_hint;