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:
parent
611b6aa57e
commit
46fdf4d1b4
3 changed files with 180 additions and 11 deletions
155
src/Ewmh.cc
155
src/Ewmh.cc
|
@ -35,7 +35,9 @@
|
|||
#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 @@ 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<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 @@ 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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue