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/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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue