diff options
-rw-r--r-- | src/Ewmh.cc | 155 | ||||
-rw-r--r-- | src/WinClient.cc | 29 | ||||
-rw-r--r-- | 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 @@ | |||
35 | #include "FbTk/I18n.hh" | 35 | #include "FbTk/I18n.hh" |
36 | #include "FbTk/XLayerItem.hh" | 36 | #include "FbTk/XLayerItem.hh" |
37 | #include "FbTk/XLayer.hh" | 37 | #include "FbTk/XLayer.hh" |
38 | #include "FbTk/FbPixmap.hh" | ||
38 | 39 | ||
40 | #include <X11/Xproto.h> | ||
39 | #include <X11/Xatom.h> | 41 | #include <X11/Xatom.h> |
40 | #include <iostream> | 42 | #include <iostream> |
41 | #include <algorithm> | 43 | #include <algorithm> |
@@ -59,6 +61,149 @@ using std::list; | |||
59 | #endif | 61 | #endif |
60 | 62 | ||
61 | 63 | ||
64 | namespace { | ||
65 | |||
66 | /* From Extended Window Manager Hints, draft 1.3: | ||
67 | * | ||
68 | * _NET_WM_ICON CARDINAL[][2+n]/32 | ||
69 | * | ||
70 | * This is an array of possible icons for the client. This specification does | ||
71 | * not stipulate what size these icons should be, but individual desktop | ||
72 | * environments or toolkits may do so. The Window Manager MAY scale any of | ||
73 | * these icons to an appropriate size. | ||
74 | * | ||
75 | * This is an array of 32bit packed CARDINAL ARGB with high byte being A, low | ||
76 | * byte being B. The first two cardinals are width, height. Data is in rows, | ||
77 | * left to right and top to bottom. | ||
78 | */ | ||
79 | void extractNetWmIcon(Atom net_wm_icon, WinClient& winclient) { | ||
80 | |||
81 | typedef std::pair<int, int> Size; | ||
82 | typedef std::map<Size, const unsigned long*> IconContainer; | ||
83 | |||
84 | // attention: the returned data for XA_CARDINAL is long if the rfmt equals | ||
85 | // 32. sizeof(long) on 64bit machines is 8. | ||
86 | unsigned long* raw_data = 0; | ||
87 | long nr_icon_data = 0; | ||
88 | |||
89 | { | ||
90 | Atom rtype; | ||
91 | int rfmt; | ||
92 | unsigned long nr_read; | ||
93 | unsigned long nr_bytes_left; | ||
94 | |||
95 | // no data or no _NET_WM_ICON | ||
96 | if (! winclient.property(net_wm_icon, 0L, 0L, False, XA_CARDINAL, | ||
97 | &rtype, &rfmt, &nr_read, &nr_bytes_left, | ||
98 | reinterpret_cast<unsigned char**>(&raw_data)) || nr_bytes_left == 0) { | ||
99 | |||
100 | if (raw_data) | ||
101 | XFree(raw_data); | ||
102 | |||
103 | return; | ||
104 | } | ||
105 | |||
106 | // actually there is some data in _NET_WM_ICON | ||
107 | nr_icon_data = nr_bytes_left / sizeof(CARD32); | ||
108 | |||
109 | // read all the icons stored in _NET_WM_ICON | ||
110 | winclient.property(net_wm_icon, 0L, nr_icon_data, False, XA_CARDINAL, | ||
111 | &rtype, &rfmt, &nr_read, &nr_bytes_left, | ||
112 | reinterpret_cast<unsigned char**>(&raw_data)); | ||
113 | } | ||
114 | |||
115 | IconContainer icon_data; // stores all available data, sorted by size (width x height) | ||
116 | int width; | ||
117 | int height; | ||
118 | |||
119 | // analyze the available icons | ||
120 | long i; | ||
121 | for (i = 0; i < nr_icon_data; i += width * height ) { | ||
122 | |||
123 | width = raw_data[i++]; | ||
124 | height = raw_data[i++]; | ||
125 | |||
126 | icon_data[Size(width, height)] = &raw_data[i]; | ||
127 | } | ||
128 | |||
129 | Display* dpy = FbTk::App::instance()->display(); | ||
130 | int scrn = winclient.screen().screenNumber(); | ||
131 | |||
132 | // pick the smallest icon size atm | ||
133 | // TODO: find a better criteria | ||
134 | width = icon_data.begin()->first.first; | ||
135 | height = icon_data.begin()->first.second; | ||
136 | |||
137 | // tmp image for the pixmap | ||
138 | XImage* img_pm = XCreateImage(dpy, DefaultVisual(dpy, scrn), winclient.depth(), | ||
139 | ZPixmap, | ||
140 | 0, NULL, width, height, 32, 0); | ||
141 | if (!img_pm) { | ||
142 | XFree(raw_data); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | // tmp image for the mask | ||
147 | XImage* img_mask = XCreateImage(dpy, DefaultVisual(dpy, scrn), 1, | ||
148 | XYBitmap, | ||
149 | 0, NULL, width, height, 32, 0); | ||
150 | |||
151 | if (!img_mask) { | ||
152 | XFree(raw_data); | ||
153 | XDestroyImage(img_pm); | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | // allocate some memory for the icons at client side | ||
158 | img_pm->data = new char[img_pm->bytes_per_line * height]; | ||
159 | img_mask->data = new char[img_mask->bytes_per_line * height]; | ||
160 | |||
161 | |||
162 | const unsigned long* src = icon_data.begin()->second; | ||
163 | unsigned int pixel; | ||
164 | int x; | ||
165 | int y; | ||
166 | unsigned char r, g, b, a; | ||
167 | |||
168 | for (y = 0; y < height; y++) { | ||
169 | for (x = 0; x < width; x++, src++) { | ||
170 | |||
171 | pixel = *src; // use only 32bit | ||
172 | |||
173 | a = ( pixel & 0xff000000 ) >> 24; | ||
174 | r = ( pixel & 0x00ff0000 ) >> 16; | ||
175 | g = ( pixel & 0x0000ff00 ) >> 8; | ||
176 | b = ( pixel & 0x000000ff ); | ||
177 | |||
178 | // transfer color data | ||
179 | XPutPixel(img_pm, x, y, pixel & 0x00ffffff ); // TODO: this only works in 24bit depth | ||
180 | |||
181 | // transfer mask data | ||
182 | XPutPixel(img_mask, x, y, a > 127 ? 0 : 1); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | // the final icon | ||
187 | FbTk::PixmapWithMask icon; | ||
188 | icon.pixmap() = FbTk::FbPixmap(winclient.drawable(), width, height, winclient.depth()); | ||
189 | icon.mask() = FbTk::FbPixmap(winclient.drawable(), width, height, 1); | ||
190 | |||
191 | FbTk::GContext gc_pm(icon.pixmap()); | ||
192 | FbTk::GContext gc_mask(icon.mask()); | ||
193 | |||
194 | XPutImage(dpy, icon.pixmap().drawable(), gc_pm.gc(), img_pm, 0, 0, 0, 0, width, height); | ||
195 | XPutImage(dpy, icon.mask().drawable(), gc_mask.gc(), img_mask, 0, 0, 0, 0, width, height); | ||
196 | |||
197 | XDestroyImage(img_pm); // also frees img_pm->data | ||
198 | XDestroyImage(img_mask); // also frees img_mask->data | ||
199 | |||
200 | XFree(raw_data); | ||
201 | |||
202 | winclient.setIcon(icon); | ||
203 | } | ||
204 | |||
205 | }; // end anonymous namespace | ||
206 | |||
62 | class Ewmh::EwmhAtoms { | 207 | class Ewmh::EwmhAtoms { |
63 | public: | 208 | public: |
64 | 209 | ||
@@ -284,6 +429,7 @@ void Ewmh::initForScreen(BScreen &screen) { | |||
284 | m_net->wm_strut, | 429 | m_net->wm_strut, |
285 | m_net->wm_state, | 430 | m_net->wm_state, |
286 | m_net->wm_name, | 431 | m_net->wm_name, |
432 | m_net->wm_icon, | ||
287 | m_net->wm_icon_name, | 433 | m_net->wm_icon_name, |
288 | 434 | ||
289 | // states that we support: | 435 | // states that we support: |
@@ -386,7 +532,11 @@ void Ewmh::setupClient(WinClient &winclient) { | |||
386 | Atom ret_type; | 532 | Atom ret_type; |
387 | int fmt; | 533 | int fmt; |
388 | unsigned long nitems, bytes_after; | 534 | unsigned long nitems, bytes_after; |
389 | unsigned char *data = 0; | 535 | unsigned char* data = 0; |
536 | |||
537 | |||
538 | extractNetWmIcon(m_net->wm_icon, winclient); | ||
539 | |||
390 | 540 | ||
391 | /* From Extended Window Manager Hints, draft 1.3: | 541 | /* From Extended Window Manager Hints, draft 1.3: |
392 | * | 542 | * |
@@ -1052,6 +1202,9 @@ bool Ewmh::propertyNotify(WinClient &winclient, Atom the_property) { | |||
1052 | } else if (the_property == m_net->wm_icon_name) { | 1202 | } else if (the_property == m_net->wm_icon_name) { |
1053 | // we don't use icon title, since we don't show icons | 1203 | // we don't use icon title, since we don't show icons |
1054 | return true; | 1204 | return true; |
1205 | } else if (the_property == m_net->wm_icon) { | ||
1206 | extractNetWmIcon(m_net->wm_icon, winclient); | ||
1207 | return true; | ||
1055 | } | 1208 | } |
1056 | 1209 | ||
1057 | return false; | 1210 | 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() { | |||
358 | titleSig().notify(); | 358 | titleSig().notify(); |
359 | } | 359 | } |
360 | 360 | ||
361 | void WinClient::setTitle(FbTk::FbString &title) { | 361 | void WinClient::setTitle(const FbTk::FbString &title) { |
362 | m_title = title; | 362 | m_title = title; |
363 | m_title_override = true; | 363 | m_title_override = true; |
364 | titleSig().notify(); | 364 | titleSig().notify(); |
365 | } | 365 | } |
366 | 366 | ||
367 | void WinClient::setIcon(const FbTk::PixmapWithMask& pm) { | ||
368 | |||
369 | m_icon.pixmap().copy(pm.pixmap()); | ||
370 | m_icon.mask().copy(pm.mask()); | ||
371 | m_icon_override = true; | ||
372 | titleSig().notify(); | ||
373 | } | ||
374 | |||
367 | void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements) { | 375 | void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements) { |
368 | changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), | 376 | changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), |
369 | XA_CARDINAL, 32, PropModeReplace, | 377 | XA_CARDINAL, 32, PropModeReplace, |
@@ -429,15 +437,18 @@ void WinClient::updateWMHints() { | |||
429 | if (wmhint->flags & WindowGroupHint && !window_group) | 437 | if (wmhint->flags & WindowGroupHint && !window_group) |
430 | window_group = wmhint->window_group; | 438 | window_group = wmhint->window_group; |
431 | 439 | ||
432 | if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) | 440 | if (! m_icon_override) { |
433 | m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0); | ||
434 | else | ||
435 | m_icon.pixmap().release(); | ||
436 | 441 | ||
437 | if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) | 442 | if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) |
438 | m_icon.mask().copy(wmhint->icon_mask, 0, 0); | 443 | m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0); |
439 | else | 444 | else |
440 | m_icon.mask().release(); | 445 | m_icon.pixmap().release(); |
446 | |||
447 | if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) | ||
448 | m_icon.mask().copy(wmhint->icon_mask, 0, 0); | ||
449 | else | ||
450 | m_icon.mask().release(); | ||
451 | } | ||
441 | 452 | ||
442 | if (fbwindow()) { | 453 | if (fbwindow()) { |
443 | if (wmhint->flags & XUrgencyHint) { | 454 | 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: | |||
59 | void updateWMProtocols(); | 59 | void updateWMProtocols(); |
60 | 60 | ||
61 | // override the title with this | 61 | // override the title with this |
62 | void setTitle(FbTk::FbString &title); | 62 | void setTitle(const FbTk::FbString &title); |
63 | void updateTitle(); | 63 | void updateTitle(); |
64 | /// updates transient window information | 64 | /// updates transient window information |
65 | void updateTransientInfo(); | 65 | void updateTransientInfo(); |
66 | 66 | ||
67 | // override the icon with this | ||
68 | void setIcon(const FbTk::PixmapWithMask& pm); | ||
69 | |||
70 | // update some thints | ||
67 | void updateMWMHints(); | 71 | void updateMWMHints(); |
68 | void updateWMHints(); | 72 | void updateWMHints(); |
69 | void updateWMNormalHints(); | 73 | void updateWMNormalHints(); |
@@ -164,6 +168,7 @@ private: | |||
164 | int m_win_gravity; | 168 | int m_win_gravity; |
165 | 169 | ||
166 | bool m_title_override; | 170 | bool m_title_override; |
171 | bool m_icon_override; | ||
167 | 172 | ||
168 | Focusable::WindowType m_window_type; | 173 | Focusable::WindowType m_window_type; |
169 | MwmHints *m_mwm_hint; | 174 | MwmHints *m_mwm_hint; |