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
This commit is contained in:
Mathias Gumz 2008-02-24 21:58:24 +01:00
parent 611b6aa57e
commit 46fdf4d1b4
3 changed files with 180 additions and 11 deletions

View file

@ -35,7 +35,9 @@
#include "FbTk/I18n.hh" #include "FbTk/I18n.hh"
#include "FbTk/XLayerItem.hh" #include "FbTk/XLayerItem.hh"
#include "FbTk/XLayer.hh" #include "FbTk/XLayer.hh"
#include "FbTk/FbPixmap.hh"
#include <X11/Xproto.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
@ -59,6 +61,149 @@ using std::list;
#endif #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 { class Ewmh::EwmhAtoms {
public: public:
@ -284,6 +429,7 @@ void Ewmh::initForScreen(BScreen &screen) {
m_net->wm_strut, m_net->wm_strut,
m_net->wm_state, m_net->wm_state,
m_net->wm_name, m_net->wm_name,
m_net->wm_icon,
m_net->wm_icon_name, m_net->wm_icon_name,
// states that we support: // states that we support:
@ -386,7 +532,11 @@ void Ewmh::setupClient(WinClient &winclient) {
Atom ret_type; Atom ret_type;
int fmt; int fmt;
unsigned long nitems, bytes_after; 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: /* 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) { } else if (the_property == m_net->wm_icon_name) {
// we don't use icon title, since we don't show icons // we don't use icon title, since we don't show icons
return true; return true;
} else if (the_property == m_net->wm_icon) {
extractNetWmIcon(m_net->wm_icon, winclient);
return true;
} }
return false; return false;

View file

@ -358,12 +358,20 @@ void WinClient::updateTitle() {
titleSig().notify(); titleSig().notify();
} }
void WinClient::setTitle(FbTk::FbString &title) { void WinClient::setTitle(const FbTk::FbString &title) {
m_title = title; m_title = title;
m_title_override = true; m_title_override = true;
titleSig().notify(); 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) { void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements) {
changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(),
XA_CARDINAL, 32, PropModeReplace, XA_CARDINAL, 32, PropModeReplace,
@ -429,15 +437,18 @@ void WinClient::updateWMHints() {
if (wmhint->flags & WindowGroupHint && !window_group) if (wmhint->flags & WindowGroupHint && !window_group)
window_group = wmhint->window_group; window_group = wmhint->window_group;
if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) if (! m_icon_override) {
m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0);
else
m_icon.pixmap().release();
if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0)
m_icon.mask().copy(wmhint->icon_mask, 0, 0); m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0);
else else
m_icon.mask().release(); 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 (fbwindow()) {
if (wmhint->flags & XUrgencyHint) { if (wmhint->flags & XUrgencyHint) {

View file

@ -59,11 +59,15 @@ public:
void updateWMProtocols(); void updateWMProtocols();
// override the title with this // override the title with this
void setTitle(FbTk::FbString &title); void setTitle(const FbTk::FbString &title);
void updateTitle(); void updateTitle();
/// updates transient window information /// updates transient window information
void updateTransientInfo(); void updateTransientInfo();
// override the icon with this
void setIcon(const FbTk::PixmapWithMask& pm);
// update some thints
void updateMWMHints(); void updateMWMHints();
void updateWMHints(); void updateWMHints();
void updateWMNormalHints(); void updateWMNormalHints();
@ -164,6 +168,7 @@ private:
int m_win_gravity; int m_win_gravity;
bool m_title_override; bool m_title_override;
bool m_icon_override;
Focusable::WindowType m_window_type; Focusable::WindowType m_window_type;
MwmHints *m_mwm_hint; MwmHints *m_mwm_hint;