diff --git a/eiconman/DesktopIcon.cpp b/eiconman/DesktopIcon.cpp index 00baebd..a17619a 100644 --- a/eiconman/DesktopIcon.cpp +++ b/eiconman/DesktopIcon.cpp @@ -34,8 +34,10 @@ // label offset from icon y()+h(), so selection box can be drawn nicely #define LABEL_OFFSET 2 +#define SHAPE 1 + DesktopIcon::DesktopIcon(GlobalIconSettings* gs, IconSettings* is, int bg) : - Fl_Button(is->x, is->y, ICONSIZE, ICONSIZE) { + Fl_Widget(is->x, is->y, ICONSIZE, ICONSIZE) { EASSERT(gs != NULL); @@ -214,7 +216,29 @@ void DesktopIcon::draw(void) { } int DesktopIcon::handle(int event) { - return Fl_Button::handle(event); + switch(event) { + case FL_FOCUS: + case FL_UNFOCUS: + case FL_ENTER: + case FL_LEAVE: + return 1; + /* + * We have to handle FL_MOVE too, if want to get only once + * FL_ENTER when entered or FL_LEAVE when leaved. + */ + case FL_MOVE: + return 1; + case FL_PUSH: + return 1; + case FL_RELEASE: + if(Fl::event_clicks() > 0) + EDEBUG(ESTRLOC ": EXECUTE: %s\n", settings->cmd.c_str()); + return 1; + default: + break; + } + + return 1; } MovableIcon::MovableIcon(DesktopIcon* ic) : Fl_Window(ic->x(), ic->y(), ic->w(), ic->h()), icon(ic) { @@ -224,7 +248,16 @@ MovableIcon::MovableIcon(DesktopIcon* ic) : Fl_Window(ic->x(), ic->y(), ic->w(), color(ic->color()); begin(); + Fl_Image* img = ic->icon_image(); + /* + * Force box be same width/height as icon so it + * can fit inside masked window. + */ +#ifdef SHAPE + icon_box = new Fl_Box(0, 0, img->w(), img->h()); +#else icon_box = new Fl_Box(0, 0, w(), h()); +#endif icon_box->image(ic->icon_image()); end(); } @@ -235,8 +268,9 @@ MovableIcon::~MovableIcon() { void MovableIcon::show(void) { if(!shown()) Fl_X::make_xid(this); -#if 0 - Pixmap mask = create_mask((Fl_RGB_Image*)icon->icon_image()); + +#ifdef SHAPE + Pixmap mask = create_mask(icon->icon_image()); XShapeCombineMask(fl_display, fl_xid(this), ShapeBounding, 0, 0, mask, ShapeSet); #endif } diff --git a/eiconman/DesktopIcon.h b/eiconman/DesktopIcon.h index feb111f..d91eb15 100644 --- a/eiconman/DesktopIcon.h +++ b/eiconman/DesktopIcon.h @@ -23,7 +23,7 @@ class GlobalIconSettings; class IconSettings; class MovableIcon; -class DesktopIcon : public Fl_Button { +class DesktopIcon : public Fl_Widget { private: IconSettings* settings; const GlobalIconSettings* globals; diff --git a/eiconman/Utils.cpp b/eiconman/Utils.cpp index 5557666..9a0e459 100644 --- a/eiconman/Utils.cpp +++ b/eiconman/Utils.cpp @@ -23,6 +23,7 @@ Atom _XA_NET_WM_WINDOW_TYPE_DESKTOP = 0; Atom _XA_NET_NUMBER_OF_DESKTOPS = 0; Atom _XA_NET_CURRENT_DESKTOP = 0; Atom _XA_NET_DESKTOP_NAMES = 0; +Atom _XA_XROOTPMAP_ID = 0; Atom _XA_EDE_DESKTOP_NOTIFY = 0; Atom _XA_EDE_DESKTOP_NOTIFY_COLOR = 0; @@ -43,6 +44,7 @@ void init_atoms(void) { _XA_NET_NUMBER_OF_DESKTOPS = XInternAtom(fl_display, "_NET_NUMBER_OF_DESKTOPS", False); _XA_NET_CURRENT_DESKTOP = XInternAtom(fl_display, "_NET_CURRENT_DESKTOP", False); _XA_NET_DESKTOP_NAMES = XInternAtom(fl_display, "_NET_DESKTOP_NAMES", False); + _XA_XROOTPMAP_ID = XInternAtom(fl_display, "_XROOTPMAP_ID", False); _XA_EDE_DESKTOP_NOTIFY = XInternAtom(fl_display, "_EDE_DESKTOP_NOTIFY", False); _XA_EDE_DESKTOP_NOTIFY_COLOR = XInternAtom(fl_display, "_EDE_DESKTOP_NOTIFY_COLOR", False); @@ -288,6 +290,64 @@ void set_xoverlay_drawable(Fl_Window* win) { overlay_drawable = win; } +Pixmap create_mask(Fl_Image* img) { + if(!img) + return 0; + + // no alpha + if(img->d() != 4) + return 0; + + int iw = img->w(); + int ih = img->h(); + + unsigned char* xim_data = new unsigned char[((iw >> 3) + 8) * ih]; + + XImage* xim = XCreateImage(fl_display, fl_visual->visual, 1, ZPixmap, 0, (char*)xim_data, iw, ih, 8, 0); + if(!xim) { + delete [] xim_data; + return 0; + } + + const char* src = img->data()[0]; + unsigned char r,g,b,a; + + for(int y = 0; y < ih; y++) { + for(int x = 0; x < iw; x++) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + + //EDEBUG("x: %i y: %i\n", x, y); + + if(a < 128) + XPutPixel(xim, x, y, 0); + else + XPutPixel(xim, x, y, 1); + } + } + + Window drawable = XCreateSimpleWindow(fl_display, RootWindow(fl_display, fl_screen), 0, 0, iw, + ih, 0, 0, BlackPixel(fl_display, fl_screen)); + + Pixmap pix = XCreatePixmap(fl_display, drawable, iw, ih, 1); + + 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); + delete [] xim->data; + xim->data = 0; + XDestroyImage(xim); + + return pix; +} + char* get_basename(const char* path) { char* p = strrchr(path, '/'); if(p) diff --git a/eiconman/Utils.h b/eiconman/Utils.h index 5185b77..66dd9b1 100644 --- a/eiconman/Utils.h +++ b/eiconman/Utils.h @@ -24,6 +24,7 @@ extern Atom _XA_NET_WM_WINDOW_TYPE_DESKTOP; extern Atom _XA_NET_NUMBER_OF_DESKTOPS; extern Atom _XA_NET_CURRENT_DESKTOP; extern Atom _XA_NET_DESKTOP_NAMES; +extern Atom _XA_XROOTPMAP_ID; // via XGetTextProperty/XSetTextProperty extern Atom _XA_EDE_DESKTOP_NOTIFY; @@ -45,7 +46,7 @@ void draw_xoverlay(int x, int y, int w, int h); void clear_xoverlay(void); void set_xoverlay_drawable(Fl_Window* win); -Pixmap create_mask(Fl_RGB_Image* img); +Pixmap create_mask(Fl_Image* img); char* get_basename(const char* path); diff --git a/eiconman/Wallpaper.cpp b/eiconman/Wallpaper.cpp index efd9d73..d89f8e0 100644 --- a/eiconman/Wallpaper.cpp +++ b/eiconman/Wallpaper.cpp @@ -11,15 +11,174 @@ */ #include "Wallpaper.h" +#include "Utils.h" #include #include #include +#include -Wallpaper::Wallpaper(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H, 0), img(NULL), tiled(false) { +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) { @@ -33,6 +192,8 @@ bool Wallpaper::set(const char* path) { img = i; image(img); + set_rootpmap(); + return true; } @@ -43,6 +204,46 @@ bool Wallpaper::set_tiled(const char* path) { 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; @@ -84,4 +285,25 @@ void Wallpaper::draw(void) { } 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 } diff --git a/eiconman/Wallpaper.h b/eiconman/Wallpaper.h index b6b5173..f3507fe 100644 --- a/eiconman/Wallpaper.h +++ b/eiconman/Wallpaper.h @@ -16,14 +16,19 @@ #include #include +#include // XImage, Pixmap + /* * Class responsible for displaying images at background * their scaling (TODO), caching(TODO) and making coffee at spear time. */ class Wallpaper : public Fl_Box { private: + XImage* rootpmap_image; + Pixmap rootpmap_pixmap; Fl_Image* img; bool tiled; + void set_rootpmap(void); public: Wallpaper(int X, int Y, int W, int H); diff --git a/eiconman/eiconman.cpp b/eiconman/eiconman.cpp index d16fbc5..34d3979 100644 --- a/eiconman/eiconman.cpp +++ b/eiconman/eiconman.cpp @@ -87,10 +87,16 @@ int desktop_xmessage_handler(int event) { return 1; } - if(fl_xevent->xclient.message_type == _XA_EDE_DESKTOP_NOTIFY_COLOR) { + //if(fl_xevent->xclient.message_type == _XA_EDE_DESKTOP_NOTIFY_COLOR) { + if(fl_xevent->xproperty.atom == _XA_EDE_DESKTOP_NOTIFY_COLOR) { Desktop::instance()->notify_box_color(ede_get_desktop_notify_color()); return 1; } + + if(fl_xevent->xproperty.atom == _XA_NET_WORKAREA) { + Desktop::instance()->update_workarea(); + return 1; + } } return 0; @@ -114,7 +120,9 @@ Desktop::Desktop() : Fl_Window(0, 0, 100, 100, "") { */ begin(); wallpaper = new Wallpaper(0, 0, w(), h()); - wallpaper->set("/home/sanel/wallpapers/katebig.jpg"); + //wallpaper->set("/home/sanel/wallpapers/katebig.jpg"); + wallpaper->set("/home/sanelz/walls/nin/1024x768-04.jpg"); + //wallpaper->set("/home/sanelz/walls/nin/1024x768-02.jpg"); notify = new NotifyBox(w(), h()); notify->hide(); end();