From 46fdf4d1b4043588b057fcc9a03f5f66b6b09354 Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Sun, 24 Feb 2008 21:58:24 +0100 Subject: 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 --- src/Ewmh.cc | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/WinClient.cc | 29 +++++++---- src/WinClient.hh | 7 ++- 3 files changed, 180 insertions(+), 11 deletions(-) diff --git a/src/Ewmh.cc b/src/Ewmh.cc index 953d474..9db7777 100644 --- a/src/Ewmh.cc +++ b/src/Ewmh.cc @@ -35,7 +35,9 @@ #include "FbTk/I18n.hh" #include "FbTk/XLayerItem.hh" #include "FbTk/XLayer.hh" +#include "FbTk/FbPixmap.hh" +#include #include #include #include @@ -59,6 +61,149 @@ using std::list; #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 Size; + typedef std::map 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(&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(&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 @@ void Ewmh::initForScreen(BScreen &screen) { 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 @@ void Ewmh::setupClient(WinClient &winclient) { 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: * @@ -1052,6 +1202,9 @@ bool Ewmh::propertyNotify(WinClient &winclient, Atom the_property) { } 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; } return false; diff --git a/src/WinClient.cc b/src/WinClient.cc index b6df606..0295481 100644 --- a/src/WinClient.cc +++ b/src/WinClient.cc @@ -358,12 +358,20 @@ void WinClient::updateTitle() { 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(); +} + void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements) { changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), XA_CARDINAL, 32, PropModeReplace, @@ -429,15 +437,18 @@ void WinClient::updateWMHints() { 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 & IconMaskHint) && wmhint->icon_mask != 0) - m_icon.mask().copy(wmhint->icon_mask, 0, 0); - else - m_icon.mask().release(); + 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 (fbwindow()) { if (wmhint->flags & XUrgencyHint) { diff --git a/src/WinClient.hh b/src/WinClient.hh index 4712627..51d5077 100644 --- a/src/WinClient.hh +++ b/src/WinClient.hh @@ -59,11 +59,15 @@ public: 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 @@ private: int m_win_gravity; bool m_title_override; + bool m_icon_override; Focusable::WindowType m_window_type; MwmHints *m_mwm_hint; -- cgit v0.11.2