/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2023 Kim Woelders * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software, its documentation and marketing & publicity * materials, and acknowledgment shall be given in the documentation, materials * and software packages that this Software was used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "E.h" #include "backgrounds.h" #include "conf.h" #include "desktops.h" #include "eimage.h" #include "emodule.h" #include "iclass.h" #include "list.h" #include "tclass.h" #include "xwin.h" #define ENABLE_DESTROY 0 /* Broken */ struct _imagestate { char *im_file; char *real_file; char got_colors; char unloadable; char transparent; char pixmapfillstyle; char bevelstyle; char rotate; EImage *im; EImageBorder *border; unsigned int bg, hi, lo, hihi, lolo; unsigned int bg_pixel, hi_pixel, lo_pixel, hihi_pixel, lolo_pixel; }; typedef struct { ImageState *normal; ImageState *hilited; ImageState *clicked; ImageState *disabled; } ImageStateArray; struct _imageclass { dlist_t list; char *name; ImageStateArray norm, active, sticky, sticky_active; EImageBorder padding; unsigned int ref_count; }; static LIST_HEAD(iclass_list); static ImageClass *ImageclassGetFallback(void); EImage * ThemeImageLoad(const char *file) { EImage *im; char *f; if (!file) return NULL; if (file[0] == '/') { im = EImageLoad(file); return im; } f = ThemeFileFind(file, FILE_TYPE_IMAGE); if (f) { im = EImageLoad(f); Efree(f); return im; } return NULL; } static void ImagestateColorsSetGray(ImageState *is, unsigned int hihi, unsigned int hi, unsigned int bg, unsigned int lo, unsigned int lolo) { if (!is) return; COLOR32_FROM_RGB(is->hihi, hihi, hihi, hihi); COLOR32_FROM_RGB(is->hi, hi, hi, hi); COLOR32_FROM_RGB(is->bg, bg, bg, bg); COLOR32_FROM_RGB(is->lo, lo, lo, lo); COLOR32_FROM_RGB(is->lolo, lolo, lolo, lolo); } static ImageState * ImagestateCreate(const char *file) { ImageState *is; is = ECALLOC(ImageState, 1); if (!is) return NULL; is->pixmapfillstyle = FILL_STRETCH; ImagestateColorsSetGray(is, 255, 200, 160, 120, 64); is->bevelstyle = BEVEL_NONE; is->im_file = Estrdup(file); return is; } static ImageState * ImagestateCreateX(unsigned int hihi, unsigned int hi, unsigned int lo, unsigned int lolo, unsigned int bg_r, unsigned int bg_g, unsigned int bg_b) { ImageState *is; is = ImagestateCreate(NULL); if (!is) return NULL; ImagestateColorsSetGray(is, hihi, hi, 0, lo, lolo); COLOR32_FROM_RGB(is->bg, bg_r, bg_g, bg_b); is->bevelstyle = BEVEL_AMIGA; return is; } static void ImagestateDestroy(ImageState *is) { if (!is) return; Efree(is->im_file); Efree(is->real_file); if (is->im) EImageFree(is->im); Efree(is->border); Efree(is); } static ImageState * ImagestateSet(ImageState **isp, const char *name) { ImageState *is; is = ImagestateCreate(name); if (*isp) ImagestateDestroy(*isp); *isp = is; return is; } static void ImagestateColorsAlloc(ImageState *is) { if (!is || is->got_colors) return; is->bg_pixel = EAllocColor(WinGetCmap(VROOT), is->bg); is->hi_pixel = EAllocColor(WinGetCmap(VROOT), is->hi); is->lo_pixel = EAllocColor(WinGetCmap(VROOT), is->lo); is->hihi_pixel = EAllocColor(WinGetCmap(VROOT), is->hihi); is->lolo_pixel = EAllocColor(WinGetCmap(VROOT), is->lolo); is->got_colors = 1; } static void ImagestateRealize(ImageState *is) { if (!is) return; if (is->im) /* Image is already loaded */ return; if (!is->real_file) { if (!is->im_file) return; /* No file - quit */ /* not loaded, load and setup */ is->real_file = ThemeFileFind(is->im_file, FILE_TYPE_IMAGE); } if (is->real_file) { if (is->rotate && !Conf.memory_paranoia) { is->im = EImageLoadOrientate(is->real_file, is->rotate); } else { is->im = EImageLoad(is->real_file); if (is->im && is->rotate) EImageOrientate(is->im, is->rotate); } } if (!is->im) { #define S(s) ((s) ? (s) : "(null)") Eprintf ("%s: Hmmm... is->im is NULL (im_file=%s real_file=%s)\n", __func__, S(is->im_file), S(is->real_file)); EFREE_NULL(is->real_file); return; } EFREE_NULL(is->im_file); EImageCheckAlpha(is->im); if (is->border) EImageSetBorder(is->im, is->border); #if 0 /* To be implemented? */ if (is->colmod) { Imlib_set_image_red_curve(pImlib_Context, is->im, is->colmod->red.map); Imlib_set_image_green_curve(pImlib_Context, is->im, is->colmod->green.map); Imlib_set_image_blue_curve(pImlib_Context, is->im, is->colmod->blue.map); } #endif } static ImageClass * ImageclassCreate(const char *name) { ImageClass *ic; ic = ECALLOC(ImageClass, 1); if (!ic) return NULL; LIST_PREPEND(ImageClass, &iclass_list, ic); ic->name = Estrdup(name); return ic; } #if ENABLE_DESTROY static void FreeImageStateArray(ImageStateArray *isa) { ImagestateDestroy(isa->normal); ImagestateDestroy(isa->hilited); ImagestateDestroy(isa->clicked); ImagestateDestroy(isa->disabled); } static void ImageclassDestroy(ImageClass *ic) { if (!ic) return; if (ic->ref_count > 0) { DialogOK("ImageClass Error!", _("%u references remain"), ic->ref_count); return; } LIST_REMOVE(ImageClass, &iclass_list, ic); Efree(ic->name); FreeImageStateArray(&(ic->norm)); FreeImageStateArray(&(ic->active)); FreeImageStateArray(&(ic->sticky)); FreeImageStateArray(&(ic->sticky_active)); Efree(ic); } #endif /* ENABLE_DESTROY */ ImageClass * ImageclassAlloc(const char *name, int fallback) { ImageClass *ic; if (!name || !name[0]) return NULL; ic = ImageclassFind(name, fallback); if (ic) ic->ref_count++; return ic; } void ImageclassFree(ImageClass *ic) { if (ic) ic->ref_count--; } const char * ImageclassGetName(ImageClass *ic) { return (ic) ? ic->name : NULL; } EImageBorder * ImageclassGetPadding(ImageClass *ic) { return (ic) ? &(ic->padding) : NULL; } static int _ImageclassMatchName(const void *data, const void *match) { return strcmp(((const ImageClass *)data)->name, (const char *)match); } ImageClass * ImageclassFind(const char *name, int fallback) { ImageClass *ic = NULL; if (name) ic = LIST_FIND(ImageClass, &iclass_list, _ImageclassMatchName, name); if (ic || !fallback) return ic; #if 0 Eprintf("%s: Get fallback (%s)\n", __func__, name); #endif return ImageclassGetFallback(); } #define ISTATE_SET_STATE(which, fallback) \ if (!ic->which) ic->which = ic->fallback; static void ImageclassPopulate(ImageClass *ic) { if (!ic || !ic->norm.normal) return; ISTATE_SET_STATE(norm.hilited, norm.normal); ISTATE_SET_STATE(norm.clicked, norm.normal); ISTATE_SET_STATE(norm.disabled, norm.normal); ISTATE_SET_STATE(active.normal, norm.normal); ISTATE_SET_STATE(active.hilited, active.normal); ISTATE_SET_STATE(active.clicked, active.normal); ISTATE_SET_STATE(active.disabled, active.normal); ISTATE_SET_STATE(sticky.normal, norm.normal); ISTATE_SET_STATE(sticky.hilited, sticky.normal); ISTATE_SET_STATE(sticky.clicked, sticky.normal); ISTATE_SET_STATE(sticky.disabled, sticky.normal); ISTATE_SET_STATE(sticky_active.normal, norm.normal); ISTATE_SET_STATE(sticky_active.hilited, sticky_active.normal); ISTATE_SET_STATE(sticky_active.clicked, sticky_active.normal); ISTATE_SET_STATE(sticky_active.disabled, sticky_active.normal); } int ImageclassConfigLoad(FILE *fs) { int err = 0; char s[FILEPATH_LEN_MAX]; char s2[FILEPATH_LEN_MAX]; char *p2; int i1; ImageClass *ic = NULL; ImageState *is = NULL; int l, r, t, b; while (GetLine(s, sizeof(s), fs)) { i1 = ConfigParseline1(s, s2, &p2, NULL); /* ic not needed */ switch (i1) { case CONFIG_CLOSE: ImageclassPopulate(ic); goto done; case CONFIG_COLORMOD: case ICLASS_COLORMOD: continue; case CONFIG_CLASSNAME: if (ImageclassFind(s2, 0)) { SkipTillEnd(fs); goto done; } ic = ImageclassCreate(s2); continue; } /* ic needed */ if (!ic) break; switch (i1) { case CONFIG_INHERIT: { ImageClass *ic2; ic2 = ImageclassFind(s2, 0); if (!ic2) goto not_ok; ic->norm = ic2->norm; ic->active = ic2->active; ic->sticky = ic2->sticky; ic->sticky_active = ic2->sticky_active; ic->padding = ic2->padding; } continue; case ICLASS_PADDING: l = r = t = b = 0; sscanf(p2, "%i %i %i %i", &l, &r, &t, &b); ic->padding.left = l; ic->padding.right = r; ic->padding.top = t; ic->padding.bottom = b; continue; case ICLASS_NORMAL: is = ImagestateSet(&ic->norm.normal, s2); continue; case ICLASS_CLICKED: is = ImagestateSet(&ic->norm.clicked, s2); continue; case ICLASS_HILITED: is = ImagestateSet(&ic->norm.hilited, s2); continue; case ICLASS_DISABLED: is = ImagestateSet(&ic->norm.disabled, s2); continue; case ICLASS_STICKY_NORMAL: is = ImagestateSet(&ic->sticky.normal, s2); continue; case ICLASS_STICKY_CLICKED: is = ImagestateSet(&ic->sticky.clicked, s2); continue; case ICLASS_STICKY_HILITED: is = ImagestateSet(&ic->sticky.hilited, s2); continue; case ICLASS_STICKY_DISABLED: is = ImagestateSet(&ic->sticky.disabled, s2); continue; case ICLASS_ACTIVE_NORMAL: is = ImagestateSet(&ic->active.normal, s2); continue; case ICLASS_ACTIVE_CLICKED: is = ImagestateSet(&ic->active.clicked, s2); continue; case ICLASS_ACTIVE_HILITED: is = ImagestateSet(&ic->active.hilited, s2); continue; case ICLASS_ACTIVE_DISABLED: is = ImagestateSet(&ic->active.disabled, s2); continue; case ICLASS_STICKY_ACTIVE_NORMAL: is = ImagestateSet(&ic->sticky_active.normal, s2); continue; case ICLASS_STICKY_ACTIVE_CLICKED: is = ImagestateSet(&ic->sticky_active.clicked, s2); continue; case ICLASS_STICKY_ACTIVE_HILITED: is = ImagestateSet(&ic->sticky_active.hilited, s2); continue; case ICLASS_STICKY_ACTIVE_DISABLED: is = ImagestateSet(&ic->sticky_active.disabled, s2); continue; } /* is needed */ if (!is) break; switch (i1) { case ICLASS_LRTB: if (!is->border) is->border = EMALLOC(EImageBorder, 1); l = r = t = b = 0; sscanf(p2, "%i %i %i %i", &l, &r, &t, &b); is->border->left = l; is->border->right = r; is->border->top = t; is->border->bottom = b; continue; case ICLASS_FILLRULE: is->pixmapfillstyle = atoi(s2); continue; case ICLASS_TRANSPARENT: is->transparent = strtoul(s2, NULL, 0); continue; case ICLASS_ROTATE: /* flip goes here too */ is->rotate = strtoul(s2, NULL, 0); continue; case ICLASS_BEVEL: { int n, bevel; n = sscanf(p2, "%i %i %i %i %i %i", &bevel, &is->hihi, &is->hi, &is->bg, &is->lo, &is->lolo); if (n < 6) goto not_ok; is->bevelstyle = bevel; } continue; default: goto not_ok; } } not_ok: err = -1; done: return err; } ImageClass * ImageclassCreateSimple(const char *name, const char *image) { ImageClass *ic; ic = ImageclassCreate(name); if (!ic) return NULL; ic->norm.normal = ImagestateCreate(image); ic->norm.normal->unloadable = 1; ImageclassPopulate(ic); ImagestateRealize(ic->norm.normal); return ic; } static ImageState * ImageclassGetImageState1(ImageStateArray *pisa, int state) { ImageState *is; switch (state) { case STATE_NORMAL: is = pisa->normal; break; case STATE_HILITED: is = pisa->hilited; break; case STATE_CLICKED: is = pisa->clicked; break; case STATE_DISABLED: is = pisa->disabled; break; default: is = NULL; break; } return is; } ImageState * ImageclassGetImageState(ImageClass *ic, int state, int active, int sticky) { ImageState *is; if (active) { if (sticky) is = ImageclassGetImageState1(&ic->sticky_active, state); else is = ImageclassGetImageState1(&ic->active, state); } else { if (sticky) is = ImageclassGetImageState1(&ic->sticky, state); else is = ImageclassGetImageState1(&ic->norm, state); } return is; } EImage * ImageclassGetImage(ImageClass *ic, int active, int sticky, int state) { EImage *im; ImageState *is; if (!ic) return NULL; is = ImageclassGetImageState(ic, state, active, sticky); if (!is) return NULL; if (!is->im) ImagestateRealize(is); im = is->im; if (!im) return NULL; is->im = NULL; return im; } char * ImageclassGetFile(ImageClass *ic) { ImageState *is; if (!ic) return NULL; is = ImageclassGetImageState(ic, STATE_NORMAL, 0, 0); if (!is || !is->im_file) return NULL; return ThemeFileFind(is->im_file, FILE_TYPE_IMAGE); } EImage * ImageclassGetImageBlended(ImageClass *ic, Win win __UNUSED__, int w, int h, int active, int sticky, int state) { ImageState *is; EImage *im, *bg; if (!ic) return NULL; is = ImageclassGetImageState(ic, state, active, sticky); if (!is) return NULL; if (!is->im) ImagestateRealize(is); im = is->im; if (!im) return NULL; if (is->pixmapfillstyle == FILL_STRETCH) { bg = EImageCreateScaled(im, 0, 0, 0, 0, w, h); } else { int iw, ih, tw, th; EImageGetSize(im, &iw, &ih); tw = w; th = h; if (is->pixmapfillstyle & FILL_TILE_H) tw = iw; if (is->pixmapfillstyle & FILL_TILE_V) th = ih; bg = EImageCreate(w, h); EImageTile(bg, im, 0, tw, th, 0, 0, w, h, 0, 0); } if ((is->unloadable) || (Conf.memory_paranoia)) { EImageFree(is->im); is->im = NULL; } return bg; } static void ImagestateMakePmapMask(ImageState *is, Win win, PmapMask *pmm, int pmapflags __UNUSED__, int w, int h) { if (is->pixmapfillstyle == FILL_STRETCH) { pmm->type = 1; pmm->pmap = pmm->mask = NoXID; pmm->w = w; pmm->h = h; EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap, &pmm->mask, w, h); } else { int ww, hh, cw, ch, pw, ph; EImageGetSize(is->im, &ww, &hh); pw = w; ph = h; if (is->pixmapfillstyle & FILL_TILE_H) pw = ww; if (is->pixmapfillstyle & FILL_TILE_V) ph = hh; if (is->pixmapfillstyle & FILL_INT_TILE_H) { cw = w / ww; if (cw * ww < w) cw++; if (cw < 1) cw = 1; pw = w / cw; } if (is->pixmapfillstyle & FILL_INT_TILE_V) { ch = h / hh; if (ch * hh < h) ch++; if (ch < 1) ch = 1; ph = h / ch; } pmm->type = 1; pmm->pmap = pmm->mask = NoXID; pmm->w = pw; pmm->h = ph; EImageRenderPixmaps(is->im, win, EIMAGE_ANTI_ALIAS, &pmm->pmap, &pmm->mask, pw, ph); } } #define LINE(x1, y1, x2, y2) \ XDrawLine(disp, win, gc, x + (x1), y + (y1), x + (x2), y + (y2)) #define RECT(x, y, w, h) \ XDrawRectangle(disp, win, gc, x, y, w, h); static void ImagestateDrawBevel(ImageState *is, EX_Drawable win, int x, int y, int w, int h) { GC gc; gc = EXCreateGC(win, 0, NULL); ImagestateColorsAlloc(is); switch (is->bevelstyle) { case BEVEL_AMIGA: XSetForeground(disp, gc, is->hihi_pixel); LINE(0, 0, w - 2, 0); LINE(0, 0, 0, h - 2); XSetForeground(disp, gc, is->lolo_pixel); LINE(1, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); break; case BEVEL_MOTIF: XSetForeground(disp, gc, is->hi_pixel); LINE(0, 0, w - 1, 0); LINE(0, 0, 0, h - 1); LINE(1, 1, w - 2, 1); LINE(1, 1, 1, h - 2); XSetForeground(disp, gc, is->lo_pixel); LINE(0, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); LINE(1, h - 2, w - 2, h - 2); LINE(w - 2, 2, w - 2, h - 2); break; case BEVEL_NEXT: XSetForeground(disp, gc, is->hihi_pixel); LINE(0, 0, w - 1, 0); LINE(0, 0, 0, h - 1); XSetForeground(disp, gc, is->hi_pixel); LINE(1, 1, w - 2, 1); LINE(1, 1, 1, h - 2); XSetForeground(disp, gc, is->lolo_pixel); LINE(1, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); XSetForeground(disp, gc, is->lo_pixel); LINE(2, h - 2, w - 2, h - 2); LINE(w - 2, 2, w - 2, h - 2); break; case BEVEL_DOUBLE: XSetForeground(disp, gc, is->hi_pixel); LINE(0, 0, w - 2, 0); LINE(0, 0, 0, h - 2); XSetForeground(disp, gc, is->lo_pixel); LINE(1, 1, w - 3, 1); LINE(1, 1, 1, h - 3); XSetForeground(disp, gc, is->lo_pixel); LINE(1, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); XSetForeground(disp, gc, is->hi_pixel); LINE(2, h - 2, w - 2, h - 2); LINE(w - 2, 2, w - 2, h - 2); break; case BEVEL_WIDEDOUBLE: XSetForeground(disp, gc, is->hihi_pixel); LINE(0, 0, w - 1, 0); LINE(0, 0, 0, h - 1); XSetForeground(disp, gc, is->hi_pixel); LINE(1, 1, w - 2, 1); LINE(1, 1, 1, h - 2); LINE(3, h - 4, w - 4, h - 4); LINE(w - 4, 3, w - 4, h - 4); XSetForeground(disp, gc, is->lolo_pixel); LINE(1, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); XSetForeground(disp, gc, is->lo_pixel); LINE(2, h - 2, w - 2, h - 2); LINE(w - 2, 2, w - 2, h - 2); LINE(3, 3, w - 4, 3); LINE(3, 3, 3, h - 4); break; case BEVEL_THINPOINT: XSetForeground(disp, gc, is->hi_pixel); LINE(0, 0, w - 2, 0); LINE(0, 0, 0, h - 2); XSetForeground(disp, gc, is->lo_pixel); LINE(1, h - 1, w - 1, h - 1); LINE(w - 1, 1, w - 1, h - 1); XSetForeground(disp, gc, is->hihi_pixel); LINE(0, 0, 1, 0); LINE(0, 0, 0, 1); XSetForeground(disp, gc, is->lolo_pixel); LINE(w - 2, h - 1, w - 1, h - 1); LINE(w - 1, h - 2, w - 1, h - 1); break; case BEVEL_THICKPOINT: XSetForeground(disp, gc, is->hi_pixel); RECT(x, y, w - 1, h - 1); break; default: break; } EXFreeGC(gc); } static void ImagestateDrawNoImg(ImageState *is, EX_Drawable draw, int x, int y, int w, int h) { ImagestateColorsAlloc(is); EXFillAreaSolid(draw, x, y, w, h, is->bg_pixel); if (is->bevelstyle != BEVEL_NONE) ImagestateDrawBevel(is, draw, x, y, w, h); } void ITApply(Win win, ImageClass *ic, ImageState *is, int state, int active, int sticky, TextClass *tc, TextState *ts, const char *text, int flags) { int w, h; if (!win || !ic) return; w = WinGetW(win); h = WinGetH(win); if (w <= 0 || h <= 0) return; if (!is) is = ImageclassGetImageState(ic, state, active, sticky); if (!is) return; if (tc && text) { if (!ts) ts = TextclassGetTextState(tc, state, active, sticky); } if (!is->im) ImagestateRealize(is); /* Imlib2 will not render pixmaps with dimensions > 8192 */ if (is->im && w <= 8192 && h <= 8192) { PmapMask pmm; ImagestateMakePmapMask(is, win, &pmm, IC_FLAG_MAKE_MASK, w, h); if (pmm.pmap) { EX_Pixmap pmap = pmm.pmap; if ((ts && text) || (is->bevelstyle != BEVEL_NONE) || (flags & ITA_BGPMAP)) { if (pmm.type != 0) { pmap = EGetWindowBackgroundPixmap(win); EXCopyAreaTiled(pmm.pmap, NoXID, pmap, 0, 0, w, h, 0, 0); } if (is->bevelstyle != BEVEL_NONE) ImagestateDrawBevel(is, pmap, 0, 0, w, h); if (ts && text) TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h, &(ic->padding), TextclassGetJustification(tc), flags & ITA_JUSTV); } /* Set window pixmap */ if (pmap == pmm.pmap) ESetWindowBackgroundPixmap(win, pmap, 0); if (pmm.w == w && pmm.h == h) EShapeSetMask(win, 0, 0, pmm.mask); else if (pmm.mask) EShapeSetMaskTiled(win, 0, 0, pmm.mask, w, h); } PmapMaskFree(&pmm); if ((is->unloadable) || (Conf.memory_paranoia)) { EImageFree(is->im); is->im = NULL; } } else { ImagestateColorsAlloc(is); if (is->bevelstyle == BEVEL_NONE && !text) { ESetWindowBackground(win, is->bg_pixel); } else { EX_Pixmap pmap; pmap = EGetWindowBackgroundPixmap(win); ImagestateDrawNoImg(is, pmap, 0, 0, w, h); if (ts && text) TextstateTextDraw(ts, win, pmap, text, 0, 0, w, h, &(ic->padding), TextclassGetJustification(tc), flags & ITA_JUSTV); } } EClearWindow(win); } void ImageclassApply(ImageClass *ic, Win win, int active, int sticky, int state) { ITApply(win, ic, NULL, state, active, sticky, NULL, NULL, NULL, 0); } static void PmapMaskTile(PmapMask *pmm, Win win, unsigned int w, unsigned int h) { EX_Pixmap pmap, mask; pmap = ECreatePixmap(win, w, h, 0); if (pmap == NoXID) return; EXCopyAreaTiled(pmm->pmap, NoXID, pmap, 0, 0, w, h, 0, 0); mask = NoXID; if (pmm->mask != NoXID) mask = ECreatePixmap(win, w, h, 1); if (mask != NoXID) EXCopyAreaTiled(pmm->mask, NoXID, mask, 0, 0, w, h, 0, 0); PmapMaskFree(pmm); pmm->type = 0; pmm->w = w; pmm->h = h; pmm->pmap = pmap; pmm->mask = mask; } void ImageclassApplyCopy(ImageClass *ic, Win win, int w, int h, int active, int sticky, int state, PmapMask *pmm, int pmapflags) { ImageState *is; if (!pmm) return; pmm->type = 0; pmm->pmap = pmm->mask = 0; if ((!ic) || (!win) || (w <= 0) || (h <= 0)) return; is = ImageclassGetImageState(ic, state, active, sticky); if (!is) return; if (!is->im) ImagestateRealize(is); /* Imlib2 will not render pixmaps with dimensions > 8192 */ if (is->im && w <= 8192 && h <= 8192) { ImagestateMakePmapMask(is, win, pmm, pmapflags, w, h); if ((pmapflags & IC_FLAG_FULL_SIZE) && pmm->pmap && (pmm->w != w || pmm->h != h)) { /* Create new full sized pixmaps and fill them with the */ /* pmap and mask tiles */ PmapMaskTile(pmm, win, w, h); } if ((is->unloadable) || (Conf.memory_paranoia)) { EImageFree(is->im); is->im = NULL; } } else { if (pmm->pmap) Eprintf("%s: Hmm... pmm->pmap already set\n", __func__); pmm->type = 0; pmm->pmap = ECreatePixmap(win, w, h, 0); pmm->mask = 0; ImagestateDrawNoImg(is, pmm->pmap, 0, 0, w, h); /* FIXME - No text */ } } void ImageclassApplySimple(ImageClass *ic, Win win, EX_Drawable draw, int state, int x, int y, int w, int h) { EImage *im; if (!ic) return; im = ImageclassGetImage(ic, 0, 0, state); if (im) { EImageRenderOnDrawable(im, win, draw, 0, x, y, w, h); EImageFree(im); } else { ImageState *is; is = ImageclassGetImageState(ic, state, 0, 0); if (!is) return; ImagestateDrawNoImg(is, draw, x, y, w, h); } } static ImageClass * ImageclassGetFallback(void) { ImageClass *ic; ic = ImageclassFind("__fb_ic", 0); if (ic) return ic; /* Create fallback imageclass */ ic = ImageclassCreate("__fb_ic"); if (!ic) return ic; ic->norm.normal = ImagestateCreateX(255, 255, 0, 0, 160, 160, 160); ic->norm.hilited = ImagestateCreateX(255, 255, 0, 0, 192, 192, 192); ic->norm.clicked = ImagestateCreateX(0, 0, 255, 255, 192, 192, 192); ic->active.normal = ImagestateCreateX(255, 255, 0, 0, 220, 0, 0); ic->active.hilited = ImagestateCreateX(255, 255, 0, 0, 255, 0, 0); ic->active.clicked = ImagestateCreateX(0, 0, 255, 255, 230, 190, 210); ic->padding.left = 4; ic->padding.right = 4; ic->padding.top = 4; ic->padding.bottom = 4; ImageclassPopulate(ic); return ic; } ImageClass * ImageclassGetBlack(void) { ImageClass *ic; ic = ImageclassFind("__BLACK", 0); if (ic) return ic; /* Create all black image class for filler borders */ ic = ImageclassCreate("__BLACK"); if (!ic) return ic; ic->norm.normal = ImagestateCreate(NULL); ImagestateColorsSetGray(ic->norm.normal, 0, 0, 0, 0, 0); ImageclassPopulate(ic); return ic; } /* * Imageclass Module */ static void ImageclassIpc(const char *params) { char param1[1024]; char param2[1024]; int l; const char *p; ImageClass *ic; if (!params) { IpcPrintf("Please specify...\n"); return; } p = params; l = 0; param1[0] = param2[0] = '\0'; sscanf(p, "%1000s %1000s %n", param1, param2, &l); p += l; if (!strncmp(param1, "list", 2)) { LIST_FOR_EACH(ImageClass, &iclass_list, ic) IpcPrintf("%s\n", ic->name); return; } if (!param1[0]) { IpcPrintf("ImageClass not specified\n"); return; } if (!strcmp(param2, "free_pixmap")) { EX_Pixmap pmap; pmap = (EX_Pixmap) strtol(p, NULL, 0); EImagePixmapsFree(pmap, NoXID); return; } ic = ImageclassFind(param1, 0); if (!ic) { IpcPrintf("ImageClass not found: %s\n", param1); return; } if (!strcmp(param2, "get_padding")) { IpcPrintf("%i %i %i %i\n", ic->padding.left, ic->padding.right, ic->padding.top, ic->padding.bottom); } else if (!strcmp(param2, "get_image_size")) { ImagestateRealize(ic->norm.normal); if (ic->norm.normal->im) { int w, h; EImageGetSize(ic->norm.normal->im, &w, &h); EImageFree(ic->norm.normal->im); IpcPrintf("%i %i\n", w, h); } } else if (!strcmp(param2, "apply")) { EX_Window xwin; Win win; char state[20]; int st, w, h; /* 3:xwin 4:state 5:w 6:h */ xwin = NoXID; state[0] = '\0'; w = h = -1; sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h); win = ECreateWinFromXwin(xwin); if (!win) return; if (!strcmp(state, "normal")) st = STATE_NORMAL; else if (!strcmp(state, "hilited")) st = STATE_HILITED; else if (!strcmp(state, "clicked")) st = STATE_CLICKED; else if (!strcmp(state, "disabled")) st = STATE_DISABLED; else st = STATE_NORMAL; ImageclassApply(ic, win, 0, 0, st); EDestroyWin(win); } else if (!strcmp(param2, "apply_copy")) { EX_Window xwin; Win win; char state[20]; int st, w, h; PmapMask pmm; /* 3:xwin 4:state 5:w 6:h */ xwin = NoXID; state[0] = '\0'; w = h = -1; sscanf(p, "%x %16s %d %d", &xwin, state, &w, &h); win = ECreateWinFromXwin(xwin); if (!win) return; if (!strcmp(state, "normal")) st = STATE_NORMAL; else if (!strcmp(state, "hilited")) st = STATE_HILITED; else if (!strcmp(state, "clicked")) st = STATE_CLICKED; else if (!strcmp(state, "disabled")) st = STATE_DISABLED; else st = STATE_NORMAL; if (w < 0 || h < 0) { IpcPrintf("Error: missing width and/or height\n"); return; } ImageclassApplyCopy(ic, win, w, h, 0, 0, st, &pmm, IC_FLAG_MAKE_MASK | IC_FLAG_FULL_SIZE); IpcPrintf("0x%08x 0x%08x\n", pmm.pmap, pmm.mask); EDestroyWin(win); } else if (!strcmp(param2, "query")) { IpcPrintf("ImageClass %s found\n", ic->name); } else if (!strcmp(param2, "ref_count")) { IpcPrintf("%u references remain\n", ic->ref_count); } else { IpcPrintf("Error: unknown operation specified\n"); } } static const IpcItem ImageclassIpcArray[] = { { ImageclassIpc, "imageclass", "ic", "List imageclasses, apply an imageclass", NULL } , }; /* * Module descriptor */ extern const EModule ModImageclass; const EModule ModImageclass = { "imageclass", "ic", NULL, MOD_ITEMS(ImageclassIpcArray), { 0, NULL } };