ede/eiconman/Wallpaper.cpp
Sanel Zukan c153f4f114 Root pixmap is set when wallpaper is choosed (pseudo transparency).
When icons are moved, correct shape is applied on that window.
...maybe something forgot to add...
2007-06-20 10:58:07 +00:00

310 lines
6.5 KiB
C++

/*
* $Id$
*
* Eiconman, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2000-2007 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
*/
#include "Wallpaper.h"
#include "Utils.h"
#include <edelib/Debug.h>
#include <FL/Fl_Shared_Image.h>
#include <FL/fl_draw.h>
#include <FL/x.h>
Pixmap create_xpixmap(Fl_Image* img, XImage* xim, Pixmap pix) {
if(!img)
return 0;
if(xim) {
if(xim->data)
delete [] xim->data;
XDestroyImage(xim);
}
if(pix)
XFreePixmap(fl_display, pix);
unsigned long rmask = fl_visual->visual->red_mask;
unsigned long gmask = fl_visual->visual->green_mask;
unsigned long bmask = fl_visual->visual->blue_mask;
unsigned long start_mask;
int start_shift;
int rshift = 0;
int gshift = 0;
int bshift = 0;
if(fl_visual->depth == 24 || fl_visual->depth == 16) {
unsigned long n;
if(fl_visual->depth == 24) {
start_shift = 24;
start_mask = 0x80000000;
} else {
start_shift = 8;
start_mask = 0x8000;
}
rshift = start_shift;
n = start_mask;
while(!(n & rmask)) {
n >>= 1;
rshift--;
}
gshift = start_shift;
n = start_mask;
while(!(n & gmask)) {
n >>= 1;
gshift--;
}
bshift = start_shift;
n = start_mask;
while(!(n & bmask)) {
n >>= 1;
bshift--;
}
}
// assume display == 16 depth
xim = XCreateImage(fl_display, fl_visual->visual, 16, ZPixmap, 0, 0, img->w(), img->h(), 16, 0);
if(xim->bits_per_pixel != 16) {
EWARNING("Visual %i not implemented yet\n", xim->bits_per_pixel);
XDestroyImage(xim);
return 0;
}
if(img->d() < 3) {
EWARNING("Only RGB(A) images is supported for now\n");
XDestroyImage(xim);
return 0;
}
int iw = img->w();
int ih = img->h();
int id = img->d();
bool msb = false;
if(ImageByteOrder(fl_display) == MSBFirst)
msb = true;
else
msb = false;
unsigned int r, g, b, tmp;
unsigned char* dest = new unsigned char[iw * ih * id];
unsigned char* destptr = dest;
unsigned char* src = (unsigned char*)img->data()[0];
for(int j = 0; j < ih; j++) {
for(int i = 0; i < iw; i++) {
r = *src++;
g = *src++;
b = *src++;
if(id == 4)
src++;
tmp = 0;
if(rshift >= 0)
tmp |= (((int)r << rshift) & rmask);
else
tmp |= (((int)r >> (-rshift)) & rmask);
if(gshift >= 0)
tmp |= (((int)g << gshift) & gmask);
else
tmp |= (((int)g >> (-gshift)) & gmask);
if(bshift >= 0)
tmp |= (((int)b << bshift) & bmask);
else
tmp |= (((int)b >> (-bshift)) & bmask);
if(msb) {
// big endian
*destptr++ = (tmp >> 8) & 0xff;
*destptr++ = (tmp & 0xff);
} else {
// little endian
*destptr++ = (tmp & 0xff);
*destptr++ = (tmp >> 8) & 0xff;
}
}
}
xim->data = (char*)dest;
/*
* Creating another window as drawable is needed since fl_window (as drawable) can't be
* used here (valid only in draw()).
*/
Window drawable = XCreateSimpleWindow(fl_display, RootWindow(fl_display, fl_screen), 0, 0, iw,
ih, 0, 0, BlackPixel(fl_display, fl_screen));
pix = XCreatePixmap(fl_display, drawable, iw, ih, fl_visual->depth);
/*
* The same applies as above;
* fl_gc can't be used here.
*/
XGCValues gcv;
gcv.graphics_exposures = False;
GC dgc = XCreateGC(fl_display, pix, GCGraphicsExposures, &gcv);
XPutImage(fl_display, pix, dgc, xim, 0, 0, 0, 0, iw, ih);
XDestroyWindow(fl_display, drawable);
XFreeGC(fl_display, dgc);
return pix;
}
Wallpaper::Wallpaper(int X, int Y, int W, int H) :
Fl_Box(X, Y, W, H, 0), rootpmap_image(NULL), rootpmap_pixmap(0), img(NULL), tiled(false) {
}
Wallpaper::~Wallpaper() {
if(rootpmap_image) {
if(rootpmap_image->data)
delete [] rootpmap_image->data;
XDestroyImage(rootpmap_image);
}
if(rootpmap_pixmap)
XFreePixmap(fl_display, rootpmap_pixmap);
}
bool Wallpaper::set(const char* path) {
EASSERT(path != NULL);
tiled = false;
Fl_Image* i = Fl_Shared_Image::get(path);
if(!i)
return false;
img = i;
image(img);
set_rootpmap();
return true;
}
bool Wallpaper::set_tiled(const char* path) {
bool ret = set(path);
if(ret)
tiled = true;
return ret;
}
void Wallpaper::set_rootpmap(void) {
if(!image())
return;
rootpmap_pixmap = create_xpixmap(image(), rootpmap_image, rootpmap_pixmap);
if(!rootpmap_pixmap)
return;
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_XROOTPMAP_ID, XA_PIXMAP, 32, PropModeReplace, (unsigned char *)&rootpmap_pixmap, 1);
#if 0
XGCValues gcv;
gcv.graphics_exposures = False;
GC dgc = XCreateGC(fl_display, pix, GCGraphicsExposures, &gcv);
XImage img;
img.byte_order = LSBFirst; // TODO: check
img.format = ZPixmap;
img.depth = fl_visual->depth; // depth of screen or depth of image() ?
// find out bits_per_pixel field
int num_pfv;
XPixmapFormatValues* pfv = 0;
XPixmapFormatValues* pfvlst = 0;
pfvlst = XListPixmapFormats(fl_display, &num_pfv);
for(pfv = pfvlst; pfv < pfvlst + num_pfv; pfv++) {
if(pfv->depth == fl_visual->depth)
break;
}
img.bits_per_pixel = pfv->bits_per_pixel;
if(img.bits_per_pixel & 7) {
EWARNING("Can't work with %i bpp !!!\n", img.bits_per_pixel);
return;
}
#endif
}
void Wallpaper::draw(void) {
if(!image())
return;
int ix, iy, iw, ih;
Fl_Image* im = image();
iw = im->w();
ih = im->h();
if(iw == 0 || ih == 0)
return;
if(ih < h() || iw < w()) {
if(tiled) {
// tile image across the box
fl_push_clip(x(), y(), w(), h());
int tx = x() - (x() % iw);
int ty = y() - (y() % ih);
int tw = w() + tx;
int th = h() + ty;
for(int j = 0; j < th; j += ih)
for(int i = 0; i < tw; i += iw)
im->draw(i, j);
fl_pop_clip();
return;
} else {
// center image in the box
ix = (w()/2) - (iw/2);
iy = (h()/2) - (ih/2);
ix += x();
iy += y();
}
} else {
ix = x();
iy = y();
}
im->draw(ix, iy);
/*
* For debugging purposes :)
* Uncommenting this (and removing GC/Window creation in create_xpixmap
* will draw _XA_XROOTPMAP_ID Pixmap directly in Wallpaper widget.
* It is used to check Fl_Image->Image conversion.
*/
#if 0
if(global_xim) {
Pixmap pix = fl_create_offscreen(image()->w(), image()->h());
fl_begin_offscreen(pix);
XPutImage(fl_display, pix, fl_gc, global_xim, 0, 0, 0, 0, image()->w(), image()->h());
fl_end_offscreen();
fl_copy_offscreen(ix, iy, image()->w(), image()->h(), pix, 0, 0);
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_XROOTPMAP_ID, XA_PIXMAP, 32, PropModeReplace, (unsigned char *)&pix, 1);
}
#endif
}