summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--otk/rendercontrol.cc130
-rw-r--r--otk/rendercontrol.hh3
-rw-r--r--src/client.cc17
-rw-r--r--src/client.hh12
-rw-r--r--src/frame.cc5
5 files changed, 119 insertions, 48 deletions
diff --git a/otk/rendercontrol.cc b/otk/rendercontrol.cc
index 8f932968..bf48d58a 100644
--- a/otk/rendercontrol.cc
+++ b/otk/rendercontrol.cc
@@ -438,62 +438,50 @@ void RenderControl::drawImage(Surface &sf, int w, int h,
unsigned long *data) const
{
pixel32 *bg = sf.pixelData();
- int x, y, c, sfw, sfh;
+ int c, sfw, sfh;
unsigned int i, e, bgi;
sfw = sf.size().width();
sfh = sf.size().height();
- x = (sfw - w) / 2;
- y = (sfh - h) / 2;
-
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- // Reduce the image size if its too big to make it fit on the surface
- int oldw = w, oldh = h;
- unsigned long *olddata = data;
- if (w > sfw) w = sfw;
- if (h > sfh) h = sfh;
- unsigned long newdata[w*h];
- if (w < oldw || h < oldh) {
- double dx = oldw / (double)w;
- double dy = oldh / (double)h;
+
+ if (w && h) {
+ // scale it
+ unsigned long *olddata = data;
+ unsigned long newdata[sfw*sfh];
+ double dx = w / (double)sfw;
+ double dy = h / (double)sfh;
double px = 0.0;
double py = 0.0;
int iy = 0;
- for (i = 0, c = 0, e = w*h; i < e; ++i) {
+ for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
newdata[i] = olddata[(int)px + iy];
- if (++c >= w) {
+ if (++c >= sfw) {
c = 0;
px = 0;
py += dy;
- iy = (int)py * oldw;
+ iy = (int)py * w;
} else
px += dx;
}
data = newdata;
- }
-
- for (i = 0, c = 0, bgi = y * sfw + x, e = w*h; i < e; ++i, ++bgi) {
- unsigned char alpha = data[i] >> 24;
- unsigned char r = data[i] >> 16;
- unsigned char g = data[i] >> 8;
- unsigned char b = data[i];
- // background color
- unsigned char bgr = bg[bgi] >> default_red_shift;
- unsigned char bgg = bg[bgi] >> default_green_shift;
- unsigned char bgb = bg[bgi] >> default_blue_shift;
+ // apply the alpha channel
+ for (i = 0, c = 0, e = sfw*sfh; i < e; ++i, ++bgi) {
+ unsigned char alpha = data[i] >> 24;
+ unsigned char r = data[i] >> 16;
+ unsigned char g = data[i] >> 8;
+ unsigned char b = data[i];
+
+ // background color
+ unsigned char bgr = bg[i] >> default_red_shift;
+ unsigned char bgg = bg[i] >> default_green_shift;
+ unsigned char bgb = bg[i] >> default_blue_shift;
- r = bgr + (((r - bgr) * alpha) >> 8);
- g = bgg + (((g - bgg) * alpha) >> 8);
- b = bgb + (((b - bgb) * alpha) >> 8);
+ r = bgr + (((r - bgr) * alpha) >> 8);
+ g = bgg + (((g - bgg) * alpha) >> 8);
+ b = bgb + (((b - bgb) * alpha) >> 8);
- bg[bgi] = (r << default_red_shift) | (g << default_green_shift) |
- (b << default_blue_shift);
-
- if (++c >= w) {
- c = 0;
- bgi += sfw - w;
+ bg[i] = (r << default_red_shift) | (g << default_green_shift) |
+ (b << default_blue_shift);
}
}
@@ -508,4 +496,68 @@ void RenderControl::drawImage(Surface &sf, int w, int h,
XDestroyImage(im);
}
+void RenderControl::drawImage(Surface &sf, Pixmap pixmap, Pixmap mask) const
+{
+ int junk, sfw, sfh, w, h, depth, mw, mh, mdepth;
+ Window wjunk;
+ const ScreenInfo *info = display->screenInfo(_screen);
+ GC mgc = 0;
+
+ assert(pixmap != None);
+
+ sfw = sf.size().width();
+ sfh = sf.size().height();
+
+ XGetGeometry(**display, pixmap, &wjunk, &junk, &junk,
+ (unsigned int*)&w, (unsigned int*)&h,
+ (unsigned int*)&junk, (unsigned int*)&depth);
+ if (mask != None) {
+ XGetGeometry(**display, mask, &wjunk, &junk, &junk,
+ (unsigned int*)&mw, (unsigned int*)&mh,
+ (unsigned int*)&junk, (unsigned int*)&mdepth);
+ if (mw != w || mh != h || mdepth != 1)
+ return;
+ }
+
+ Pixmap p = XCreatePixmap(**display, info->rootWindow(), sfw, sfh,
+ info->depth());
+ Pixmap m;
+ if (mask == None)
+ m = None;
+ else {
+ m = XCreatePixmap(**display, info->rootWindow(), sfw, sfh, 1);
+ XGCValues gcv;
+ gcv.subwindow_mode = IncludeInferiors;
+ gcv.graphics_exposures = false;
+ mgc = XCreateGC(**display, m, GCGraphicsExposures |
+ GCSubwindowMode, &gcv);
+ }
+
+ // scale it
+ for (int y = sfh - 1; y >= 0; --y) {
+ int yy = y * h / sfh;
+ for (int x = sfw - 1; x >= 0; --x) {
+ int xx = x * w / sfw;
+ if (depth != info->depth()) {
+ XCopyPlane(**display, pixmap, p, DefaultGC(**display, _screen),
+ xx, yy, 1, 1, x, y, 1);
+ } else {
+ XCopyArea(**display, pixmap, p, DefaultGC(**display, _screen),
+ xx, yy, 1, 1, x, y);
+ }
+ if (mask != None)
+ XCopyArea(**display, mask, m, mgc, xx, yy, 1, 1, x, y);
+ }
+ }
+
+ XSetClipMask(**display, DefaultGC(**display, _screen), m);
+ XSetClipOrigin(**display, DefaultGC(**display, _screen), 0, 0);
+ XCopyArea(**display, p, sf.pixmap(), DefaultGC(**display, _screen), 0, 0,
+ sfw, sfh, 0, 0);
+ XSetClipMask(**display, DefaultGC(**display, _screen), None);
+
+ XFreePixmap(**display, p);
+ if (m != None) XFreePixmap(**display, m);
+}
+
}
diff --git a/otk/rendercontrol.hh b/otk/rendercontrol.hh
index 5e21da29..ff9d313d 100644
--- a/otk/rendercontrol.hh
+++ b/otk/rendercontrol.hh
@@ -64,6 +64,9 @@ public:
virtual void drawImage(Surface &sf, int w, int h,
unsigned long *data) const;
+ //! Draws an image onto the surface
+ virtual void drawImage(Surface &sf, Pixmap pixmap, Pixmap mask) const;
+
//! Draws a string onto a Surface
virtual void drawString(Surface &sf, const Font &font, int x, int y,
const RenderColor &color,
diff --git a/src/client.cc b/src/client.cc
index 7bf72645..53a6d768 100644
--- a/src/client.cc
+++ b/src/client.cc
@@ -576,6 +576,17 @@ void Client::updateWMHints(bool initstate)
} else // no group!
_group = None;
+ if (hints->flags & IconPixmapHint) {
+ updateKwmIcon(); // try get the kwm icon first, this is a fallback only
+ if (_pixmap_icon == None) {
+ _pixmap_icon = hints->icon_pixmap;
+ if (hints->flags & IconMaskHint)
+ _pixmap_icon_mask = hints->icon_mask;
+ else
+ _pixmap_icon_mask = None;
+ }
+ }
+
XFree(hints);
}
@@ -758,15 +769,15 @@ void Client::updateIcons()
void Client::updateKwmIcon()
{
- _kwm_icon = _kwm_icon_mask = None;
+ _pixmap_icon = _pixmap_icon_mask = None;
unsigned long num = 2;
Pixmap *data;
if (otk::Property::get(_window, otk::Property::atoms.kwm_win_icon,
otk::Property::atoms.kwm_win_icon, &num, &data)) {
if (num >= 2) {
- _kwm_icon = data[0];
- _kwm_icon_mask = data[1];
+ _pixmap_icon = data[0];
+ _pixmap_icon_mask = data[1];
}
delete [] data;
}
diff --git a/src/client.hh b/src/client.hh
index 8d97bfcc..932bac16 100644
--- a/src/client.hh
+++ b/src/client.hh
@@ -348,8 +348,8 @@ private:
//! The number of icons in _icons
int _nicons;
- Pixmap _kwm_icon;
- Pixmap _kwm_icon_mask;
+ Pixmap _pixmap_icon;
+ Pixmap _pixmap_icon_mask;
//! Retrieves the window's initial gravity
void getGravity();
@@ -665,16 +665,16 @@ BB @param window The window id that the Client class should handle
*/
const Icon *icon(const otk::Size &s) const;
- //! Returns the pixmap for the KWM_WIN_ICON specified on the window (or None)
+ //! Returns the pixmap for the pixmap icon specified on the window (or None)
/*!
The icon given by Client::icon should take precedence over this icon/mask.
*/
- Pixmap kwmIcon() const { return _kwm_icon; }
- //! Returns the mask for the KWM_WIN_ICON specified on the window (or None)
+ Pixmap pixmapIcon() const { return _pixmap_icon; }
+ //! Returns the mask for the pixmap icon specified on the window (or None)
/*!
The icon given by Client::icon should take precedence over this icon/mask.
*/
- Pixmap kwmIconMask() const { return _kwm_icon_mask; }
+ Pixmap pixmapIconMask() const { return _pixmap_icon_mask; }
//! Move the window (actually, its frame) to a position.
/*!
diff --git a/src/frame.cc b/src/frame.cc
index d1c206e7..23742be8 100644
--- a/src/frame.cc
+++ b/src/frame.cc
@@ -557,6 +557,11 @@ void Frame::renderIcon()
const Icon *icon = _client->icon(otk::Size(geom.button_size,
geom.button_size));
control->drawImage(*s, icon->w, icon->h, icon->data);
+ if (!icon->data) {
+ Pixmap p = _client->pixmapIcon(), m = _client->pixmapIconMask();
+ if (p != None)
+ control->drawImage(*s, p, m);
+ }
XSetWindowBackgroundPixmap(**otk::display, _icon, s->pixmap());
XClearWindow(**otk::display, _icon);