/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2009 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 #include "E.h" #include "backgrounds.h" #include "desktops.h" #include "dialog.h" #include "e16-ecore_list.h" #include "eimage.h" #include "emodule.h" #include "file.h" #include "iclass.h" #include "settings.h" #include "tclass.h" #include "timers.h" #include "xwin.h" typedef struct { char *file; char *real_file; EImage *im; char keep_aspect; int xjust, yjust; int xperc, yperc; } BgPart; struct _background { char *name; Pixmap pmap; time_t last_viewed; unsigned int bg_solid; char bg_tile; BgPart bg; BgPart top; char external; char keepim; char referenced; unsigned int ref_count; unsigned int seq_no; }; static Ecore_List *bg_list = NULL; static Timer *bg_timer = NULL; static unsigned int bg_seq_no = 0; #define N_BG_ASSIGNED 32 static Background *bg_assigned[N_BG_ASSIGNED]; char * BackgroundGetUniqueString(const Background * bg) { char s[256]; const char *chmap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"; int r, g, b; int n1, n2, n3, n4, n5, f1, f2, f3, f4, f5, f6; COLOR32_TO_RGB(bg->bg_solid, r, g, b); n1 = (r << 24) | (g << 16) | (b << 8) | (bg->bg_tile << 7) | (bg->bg.keep_aspect << 6) | (bg->top.keep_aspect << 5); n2 = (bg->bg.xjust << 16) | (bg->bg.yjust); n3 = (bg->bg.xperc << 16) | (bg->bg.yperc); n4 = (bg->top.xjust << 16) | (bg->top.yjust); n5 = (bg->top.xperc << 16) | (bg->top.yperc); f1 = 0; f2 = 0; f3 = 0; f4 = 0; f5 = 0; f6 = 0; if (bg->bg.file) { char *f; f = ThemeFileFind(bg->bg.file); if (f) { f1 = fileinode(f); f2 = filedev(f); f3 = (int)moddate(f); Efree(f); } } if (bg->top.file) { char *f; f = ThemeFileFind(bg->top.file); if (f) { f4 = fileinode(f); f5 = filedev(f); f6 = (int)moddate(f); Efree(f); } } Esnprintf(s, sizeof(s), "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c", chmap[(n1 >> 0) & 0x3f], chmap[(n1 >> 6) & 0x3f], chmap[(n1 >> 12) & 0x3f], chmap[(n1 >> 18) & 0x3f], chmap[(n1 >> 24) & 0x3f], chmap[(n1 >> 28) & 0x3f], chmap[(n2 >> 0) & 0x3f], chmap[(n2 >> 6) & 0x3f], chmap[(n2 >> 12) & 0x3f], chmap[(n2 >> 18) & 0x3f], chmap[(n2 >> 24) & 0x3f], chmap[(n2 >> 28) & 0x3f], chmap[(n3 >> 0) & 0x3f], chmap[(n3 >> 6) & 0x3f], chmap[(n3 >> 12) & 0x3f], chmap[(n3 >> 18) & 0x3f], chmap[(n3 >> 24) & 0x3f], chmap[(n3 >> 28) & 0x3f], chmap[(n4 >> 0) & 0x3f], chmap[(n4 >> 6) & 0x3f], chmap[(n4 >> 12) & 0x3f], chmap[(n4 >> 18) & 0x3f], chmap[(n4 >> 24) & 0x3f], chmap[(n4 >> 28) & 0x3f], chmap[(n5 >> 0) & 0x3f], chmap[(n5 >> 6) & 0x3f], chmap[(n5 >> 12) & 0x3f], chmap[(n5 >> 18) & 0x3f], chmap[(n5 >> 24) & 0x3f], chmap[(n5 >> 28) & 0x3f], chmap[(f1 >> 0) & 0x3f], chmap[(f1 >> 6) & 0x3f], chmap[(f1 >> 12) & 0x3f], chmap[(f1 >> 18) & 0x3f], chmap[(f1 >> 24) & 0x3f], chmap[(f1 >> 28) & 0x3f], chmap[(f2 >> 0) & 0x3f], chmap[(f2 >> 6) & 0x3f], chmap[(f2 >> 12) & 0x3f], chmap[(f2 >> 18) & 0x3f], chmap[(f2 >> 24) & 0x3f], chmap[(f2 >> 28) & 0x3f], chmap[(f3 >> 0) & 0x3f], chmap[(f3 >> 6) & 0x3f], chmap[(f3 >> 12) & 0x3f], chmap[(f3 >> 18) & 0x3f], chmap[(f3 >> 24) & 0x3f], chmap[(f3 >> 28) & 0x3f], chmap[(f4 >> 0) & 0x3f], chmap[(f4 >> 6) & 0x3f], chmap[(f4 >> 12) & 0x3f], chmap[(f4 >> 18) & 0x3f], chmap[(f4 >> 24) & 0x3f], chmap[(f4 >> 28) & 0x3f], chmap[(f5 >> 0) & 0x3f], chmap[(f5 >> 6) & 0x3f], chmap[(f5 >> 12) & 0x3f], chmap[(f5 >> 18) & 0x3f], chmap[(f5 >> 24) & 0x3f], chmap[(f5 >> 28) & 0x3f], chmap[(f6 >> 0) & 0x3f], chmap[(f6 >> 6) & 0x3f], chmap[(f6 >> 12) & 0x3f], chmap[(f6 >> 18) & 0x3f], chmap[(f6 >> 24) & 0x3f], chmap[(f6 >> 28) & 0x3f]); return Estrdup(s); } void BackgroundPixmapSet(Background * bg, Pixmap pmap) { if (bg->pmap != None && bg->pmap != pmap) Eprintf("*** BackgroundPixmapSet %s: pmap was set %#lx/%#lx\n", bg->name, bg->pmap, pmap); bg->pmap = pmap; } static void BackgroundPixmapFree(Background * bg) { if (bg->pmap) { EImagePixmapsFree(bg->pmap, None); bg->pmap = None; } } static void BackgroundImagesFree(Background * bg) { if (bg->bg.im) { EImageFree(bg->bg.im); bg->bg.im = NULL; } if (bg->top.im) { EImageFree(bg->top.im); bg->top.im = NULL; } } #if ENABLE_DIALOGS static void BackgroundImagesKeep(Background * bg, int onoff) { if (onoff) { bg->keepim = 1; } else { bg->keepim = 0; BackgroundImagesFree(bg); } } #endif /* ENABLE_DIALOGS */ static void BackgroundFilesRemove(Background * bg) { Efree(bg->bg.file); bg->bg.file = NULL; Efree(bg->bg.real_file); bg->bg.real_file = NULL; Efree(bg->top.file); bg->top.file = NULL; Efree(bg->top.real_file); bg->top.real_file = NULL; BackgroundImagesFree(bg); bg->keepim = 0; } static int BackgroundDestroy(Background * bg) { if (!bg) return -1; if (bg->ref_count > 0) { DialogOK("Background Error!", _("%u references remain\n"), bg->ref_count); return -1; } ecore_list_node_remove(bg_list, bg); BackgroundFilesRemove(bg); BackgroundPixmapFree(bg); Efree(bg->name); Efree(bg); return 0; } #if ENABLE_DIALOGS static void BackgroundDelete(Background * bg) { char *f; if (BackgroundDestroy(bg)) return; /* And delete the actual image files */ if (bg->bg.file) { f = ThemeFileFind(bg->bg.file); if (f) { E_rm(f); Efree(f); } } if (bg->top.file) { f = ThemeFileFind(bg->top.file); if (f) { E_rm(f); Efree(f); } } } #endif /* ENABLE_DIALOGS */ static Background * BackgroundCreate(const char *name, unsigned int solid, const char *bgn, char tile, char keep_aspect, int xjust, int yjust, int xperc, int yperc, const char *top, char tkeep_aspect, int txjust, int tyjust, int txperc, int typerc) { Background *bg; bg = ECALLOC(Background, 1); if (!bg) return NULL; if (!name) { name = "NONE"; bg->external = 1; } bg->name = Estrdup(name); COLOR32_FROM_RGB(bg->bg_solid, 160, 160, 160); bg->bg_solid = solid; if (bgn) bg->bg.file = Estrdup(bgn); bg->bg_tile = tile; bg->bg.keep_aspect = keep_aspect; bg->bg.xjust = xjust; bg->bg.yjust = yjust; bg->bg.xperc = xperc; bg->bg.yperc = yperc; if (top) bg->top.file = Estrdup(top); bg->top.keep_aspect = tkeep_aspect; bg->top.xjust = txjust; bg->top.yjust = tyjust; bg->top.xperc = txperc; bg->top.yperc = typerc; bg->seq_no = ++bg_seq_no; if (!bg_list) bg_list = ecore_list_new(); ecore_list_prepend(bg_list, bg); return bg; } static int BackgroundCmp(Background * bg, Background * bgx) { if (*bgx->name != '.') /* Discard only generated backgrounds */ return 1; if (bg->bg.file && bgx->bg.file) { if ((strcmp(bg->bg.file, bgx->bg.file)) || (bg->bg.keep_aspect != bgx->bg.keep_aspect) || (bg->bg.xjust != bgx->bg.xjust || bg->bg.xjust != bgx->bg.xjust) || (bg->bg.xperc != bgx->bg.xperc || bg->bg.xperc != bgx->bg.xperc)) return 1; } else if (bg->bg.file || bgx->bg.file) return 1; if (bg->top.file && bgx->top.file) { if ((strcmp(bg->top.file, bgx->top.file)) || (bg->top.keep_aspect != bgx->top.keep_aspect) || (bg->top.xjust != bgx->top.xjust || bg->top.xjust != bgx->top.xjust) || (bg->top.xperc != bgx->top.xperc || bg->top.xperc != bgx->top.xperc)) return 1; } else if (bg->top.file || bgx->top.file) return 1; if (bg->bg_solid != bgx->bg_solid) return 1; if (bg->bg_tile != bgx->bg_tile) return 1; return 0; } static int _BackgroundMatchName(const void *data, const void *match) { return strcmp(((const Background *)data)->name, (const char *)match); } Background * BackgroundFind(const char *name) { return (Background *) ecore_list_find(bg_list, _BackgroundMatchName, name); } static Background * BackgroundCheck(Background * bg) { return (Background *) ecore_list_goto(bg_list, bg); } void BackgroundDestroyByName(const char *name) { BackgroundDestroy(BackgroundFind(name)); } static void BackgroundInvalidate(Background * bg, int refresh) { BackgroundPixmapFree(bg); bg->seq_no = ++bg_seq_no; if (bg->ref_count && refresh) DesksBackgroundRefresh(bg, DESK_BG_REFRESH); } static int BackgroundModify(Background * bg, unsigned int solid, const char *bgn, char tile, char keep_aspect, int xjust, int yjust, int xperc, int yperc, const char *top, char tkeep_aspect, int txjust, int tyjust, int txperc, int typerc) { int updated = 0; if (solid != bg->bg_solid) updated = 1; bg->bg_solid = solid; if ((bg->bg.file) && (bgn)) { if (strcmp(bg->bg.file, bgn)) updated = 1; } else updated = 1; Efree(bg->bg.file); bg->bg.file = (bgn[0]) ? Estrdup(bgn) : NULL; if ((int)tile != bg->bg_tile) updated = 1; if ((int)keep_aspect != bg->bg.keep_aspect) updated = 1; if (xjust != bg->bg.xjust) updated = 1; if (yjust != bg->bg.yjust) updated = 1; if (xperc != bg->bg.xperc) updated = 1; if (yperc != bg->bg.yperc) updated = 1; bg->bg_tile = (char)tile; bg->bg.keep_aspect = (char)keep_aspect; bg->bg.xjust = xjust; bg->bg.yjust = yjust; bg->bg.xperc = xperc; bg->bg.yperc = yperc; if ((bg->top.file) && (top)) { if (strcmp(bg->top.file, top)) updated = 1; } else updated = 1; Efree(bg->top.file); bg->top.file = (top[0]) ? Estrdup(top) : NULL; if ((int)tkeep_aspect != bg->top.keep_aspect) updated = 1; if (txjust != bg->top.xjust) updated = 1; if (tyjust != bg->top.yjust) updated = 1; if (txperc != bg->top.xperc) updated = 1; if (typerc != bg->top.yperc) updated = 1; bg->top.keep_aspect = (char)tkeep_aspect; bg->top.xjust = txjust; bg->top.yjust = tyjust; bg->top.xperc = txperc; bg->top.yperc = typerc; if (updated) BackgroundInvalidate(bg, 1); return updated; } static void BgFindImageSize(BgPart * bgp, unsigned int rw, unsigned int rh, unsigned int *pw, unsigned int *ph) { int w, h, iw, ih; EImageGetSize(bgp->im, &iw, &ih); #if 0 /* FIXME - Remove? */ if (bgp->keep_aspect) bgp->xperc = bgp->yperc; #endif if (bgp->xperc > 0) w = (rw * bgp->xperc) >> 10; else w = (iw * rw) / WinGetW(VROOT); if (bgp->yperc > 0) h = (rh * bgp->yperc) >> 10; else h = (ih * rh) / WinGetH(VROOT); if (w <= 0) w = 1; if (h <= 0) h = 1; if (bgp->keep_aspect) { if (bgp->yperc <= 0) { if (((w << 10) / h) != ((iw << 10) / ih)) h = ((w * ih) / iw); } else { if (((h << 10) / w) != ((ih << 10) / iw)) w = ((h * iw) / ih); } } *pw = (unsigned int)w; *ph = (unsigned int)h; } static Pixmap BackgroundCreatePixmap(Win win, unsigned int w, unsigned int h) { Pixmap pmap; /* * Stupid hack to avoid that a new root pixmap has the same ID as the now * invalid one from a previous session. */ pmap = ECreatePixmap(win, w, h, 0); if (win == RROOT && pmap == Mode.root.ext_pmap) { EFreePixmap(pmap); pmap = ECreatePixmap(win, w, h, 0); Mode.root.ext_pmap = None; Mode.root.ext_pmap_valid = 0; } return pmap; } void BackgroundRealize(Background * bg, Win win, Drawable draw, unsigned int rw, unsigned int rh, int is_win, Pixmap * ppmap, unsigned long *ppixel) { Pixmap pmap; GC gc; int x, y, ww, hh; unsigned int w, h; char hasbg, hasfg; EImage *im; if (bg->bg.file && !bg->bg.im) { if (!bg->bg.real_file) bg->bg.real_file = ThemeFileFind(bg->bg.file); if (bg->bg.real_file) bg->bg.im = EImageLoad(bg->bg.real_file); } if (bg->top.file && !bg->top.im) { if (!bg->top.real_file) bg->top.real_file = ThemeFileFind(bg->top.file); if (bg->top.real_file) bg->top.im = EImageLoad(bg->top.real_file); } if (!draw) draw = WinGetXwin(win); hasbg = bg->bg.im != NULL; hasfg = bg->top.im != NULL; if (!hasbg && !hasfg) { unsigned int pixel; /* Solid color only */ pixel = EAllocColor(WinGetCmap(VROOT), bg->bg_solid); if (!is_win) { gc = EXCreateGC(draw, 0, NULL); XSetClipMask(disp, gc, 0); XSetFillStyle(disp, gc, FillSolid); XSetForeground(disp, gc, pixel); XFillRectangle(disp, draw, gc, 0, 0, rw, rh); EXFreeGC(gc); } if (ppmap) *ppmap = None; if (ppixel) *ppixel = pixel; return; } /* Has either bg or fg image */ w = h = x = y = 0; if (hasbg) { BgFindImageSize(&(bg->bg), rw, rh, &w, &h); x = ((int)(rw - w) * bg->bg.xjust) >> 10; y = ((int)(rh - h) * bg->bg.yjust) >> 10; } if (is_win && hasbg && !hasfg && x == 0 && y == 0 && ((w == rw && h == rh) || (bg->bg_tile && !TransparencyEnabled()))) { /* Window, no fg, no offset, and scale to 100%, or tiled, no trans */ pmap = BackgroundCreatePixmap(win, w, h); EImageRenderOnDrawable(bg->bg.im, win, pmap, EIMAGE_ANTI_ALIAS, 0, 0, w, h); #if 0 /* FIXME - Remove? */ if (x == 0 && y == 0) /* Hmmm. Always true. */ { ESetWindowBackgroundPixmap(draw, pmap); } else { gc = EXCreateGC(draw, 0, NULL); XSetTile(disp, gc, pmap); XSetTSOrigin(disp, gc, x, y); XSetFillStyle(disp, gc, FillTiled); XFillRectangle(disp, draw, gc, 0, 0, rw, rh); EXFreeGC(gc); } #endif goto done; } /* The rest that require some more work */ if (is_win) pmap = BackgroundCreatePixmap(win, rw, rh); else pmap = draw; if (hasbg && !hasfg && x == 0 && y == 0 && w == rw && h == rh) { im = bg->bg.im; } else { /* Create full size image */ im = EImageCreate(rw, rh); EImageSetHasAlpha(im, 0); if (!hasbg || !bg->bg_tile) { /* Fill solid */ EImageFill(im, 0, 0, rw, rh, bg->bg_solid); } if (hasbg) { if (bg->bg_tile) { EImageTile(im, bg->bg.im, 0, w, h, 0, 0, rw, rh, x, y); } else { EImageGetSize(bg->bg.im, &ww, &hh); EImageBlend(im, bg->bg.im, EIMAGE_ANTI_ALIAS, 0, 0, ww, hh, x, y, w, h, 1); } } } if (hasfg) { EImageGetSize(bg->top.im, &ww, &hh); BgFindImageSize(&(bg->top), rw, rh, &w, &h); x = ((rw - w) * bg->top.xjust) >> 10; y = ((rh - h) * bg->top.yjust) >> 10; EImageBlend(im, bg->top.im, EIMAGE_BLEND | EIMAGE_ANTI_ALIAS, 0, 0, ww, hh, x, y, w, h, 0); } EImageRenderOnDrawable(im, win, pmap, EIMAGE_ANTI_ALIAS, 0, 0, rw, rh); if (im != bg->bg.im) EImageFree(im); done: if (!bg->keepim) BackgroundImagesFree(bg); if (ppmap) *ppmap = pmap; if (ppixel) *ppixel = 0; } void BackgroundApplyPmap(Background * bg, Win win, Drawable draw, unsigned int w, unsigned int h) { BackgroundRealize(bg, win, draw, w, h, 0, NULL, NULL); } static void BackgroundApplyWin(Background * bg, Win win) { int w, h; Pixmap pmap; unsigned long pixel; if (!EGetGeometry(win, NULL, NULL, NULL, &w, &h, NULL, NULL)) return; BackgroundRealize(bg, win, None, w, h, 1, &pmap, &pixel); if (pmap != None) { ESetWindowBackgroundPixmap(win, pmap); EImagePixmapsFree(pmap, None); } else { ESetWindowBackground(win, pixel); } EClearWindow(win); } /* * Apply a background to window. * The BG pixmap is stored in bg->pmap. */ void BackgroundSet(Background * bg, Win win, unsigned int w, unsigned int h) { Pixmap pmap = None; unsigned long pixel = 0; if (bg->pmap) pmap = bg->pmap; else BackgroundRealize(bg, win, None, w, h, 1, &pmap, &pixel); bg->pmap = pmap; if (pmap != None) ESetWindowBackgroundPixmap(win, pmap); else ESetWindowBackground(win, pixel); EClearWindow(win); } Background * BrackgroundCreateFromImage(const char *bgid, const char *file, char *thumb, int thlen) { Background *bg; EImage *im, *im2; unsigned int color; char tile = 1, keep_asp = 0; int width, height; int scalex = 0, scaley = 0; int scr_asp, im_asp; int w2, h2; int maxw = 48, maxh = 48; int justx = 512, justy = 512; bg = BackgroundFind(bgid); if (thumb) { Esnprintf(thumb, thlen, "%s/cached/img/%s.png", EDirUserCache(), bgid); if (bg && exists(thumb) && moddate(thumb) > moddate(file)) return bg; /* The thumbnail is gone or outdated - regererate */ } else { if (bg) return bg; } im = EImageLoad(file); if (!im) return NULL; EImageGetSize(im, &width, &height); if (thumb) { h2 = maxh; w2 = (width * h2) / height; if (w2 > maxw) { w2 = maxw; h2 = (height * w2) / width; } im2 = EImageCreateScaled(im, 0, 0, width, height, w2, h2); EImageSave(im2, thumb); EImageDecache(im2); } EImageDecache(im); /* Quit if the background itself already exists */ if (bg) return bg; scr_asp = (WinGetW(VROOT) << 16) / WinGetH(VROOT); im_asp = (width << 16) / height; if (width == height) { justx = 0; justy = 0; scalex = 0; scaley = 0; tile = 1; keep_asp = 0; } else if ((!(IN_RANGE(scr_asp, im_asp, 16000))) && ((width < 480) && (height < 360))) { justx = 0; justy = 0; scalex = 0; scaley = 0; tile = 1; keep_asp = 0; } else if (IN_RANGE(scr_asp, im_asp, 16000)) { justx = 0; justy = 0; scalex = 1024; scaley = 1024; tile = 0; keep_asp = 0; } else if (im_asp > scr_asp) { justx = 512; justy = 512; scalex = 1024; scaley = 0; tile = 0; keep_asp = 1; } else { justx = 512; justy = 512; scalex = 0; scaley = 1024; tile = 0; keep_asp = 1; } COLOR32_FROM_RGB(color, 0, 0, 0); bg = BackgroundCreate(bgid, color, file, tile, keep_asp, justx, justy, scalex, scaley, NULL, 0, 0, 0, 0, 0); return bg; } void BackgroundIncRefcount(Background * bg) { if (bg == NULL) return; bg->ref_count++; } void BackgroundDecRefcount(Background * bg) { if (bg == NULL) return; bg->ref_count--; if (bg->ref_count <= 0) bg->last_viewed = 0; /* Clean out asap */ } void BackgroundTouch(Background * bg) { if (bg == NULL) return; bg->last_viewed = time(NULL); } const char * BackgroundGetName(const Background * bg) { return bg->name; } #if ENABLE_DIALOGS static const char * BackgroundGetBgFile(const Background * bg) { return bg->bg.file; } static const char * BackgroundGetFgFile(const Background * bg) { return bg->top.file; } #endif /* ENABLE_DIALOGS */ Pixmap BackgroundGetPixmap(const Background * bg) { return (bg) ? bg->pmap : None; } unsigned int BackgroundGetSeqNo(const Background * bg) { return bg->seq_no; } int BackgroundIsNone(const Background * bg) { return (bg) ? bg->external : 1; } #if ENABLE_DIALOGS static EImage * BackgroundCacheMini(Background * bg, int keep, int nuke) { char s[4096]; EImage *im; Pixmap pmap; Esnprintf(s, sizeof(s), "%s/cached/bgsel/%s.png", EDirUserCache(), BackgroundGetName(bg)); im = EImageLoad(s); if (im) { if (nuke) EImageDecache(im); else goto done; } /* Create new cached bg mini image */ pmap = ECreatePixmap(VROOT, 64, 48, 0); BackgroundApplyPmap(bg, VROOT, pmap, 64, 48); im = EImageGrabDrawable(pmap, None, 0, 0, 64, 48, 0); EImageSave(im, s); EFreePixmap(pmap); done: if (keep) return im; EImageFree(im); return NULL; } #endif /* ENABLE_DIALOGS */ #define S(str) ((str) ? str : "(null)") static void BackgroundGetInfoString1(const Background * bg, char *buf, int len) { int r, g, b; COLOR32_TO_RGB(bg->bg_solid, r, g, b); Esnprintf(buf, len, "%s ref_count %u keepim %u\n" " bg.solid\t %i %i %i \n" " bg.file\t %s\n" " top.file\t %s \n" " bg.tile\t %i \n" " bg.keep_aspect\t %i \ttop.keep_aspect\t %i \n" " bg.xjust\t %i \ttop.xjust\t %i \n" " bg.yjust\t %i \ttop.yjust\t %i \n" " bg.xperc\t %i \ttop.xperc\t %i \n" " bg.yperc\t %i \ttop.yperc\t %i \n", bg->name, bg->ref_count, bg->keepim, r, g, b, bg->bg.file, bg->top.file, bg->bg_tile, bg->bg.keep_aspect, bg->top.keep_aspect, bg->bg.xjust, bg->top.xjust, bg->bg.yjust, bg->top.yjust, bg->bg.xperc, bg->top.xperc, bg->bg.yperc, bg->top.yperc); } static void BackgroundGetInfoString2(const Background * bg, char *buf, int len) { int r, g, b; COLOR32_TO_RGB(bg->bg_solid, r, g, b); Esnprintf(buf, len, "%s %i %i %i %s %i %i %i %i %i %i %s %i %i %i %i %i", bg->name, r, g, b, S(bg->bg.file), bg->bg_tile, bg->bg.keep_aspect, bg->bg.xjust, bg->bg.yjust, bg->bg.xperc, bg->bg.yperc, S(bg->top.file), bg->top.keep_aspect, bg->top.xjust, bg->top.yjust, bg->top.xperc, bg->top.yperc); } void BackgroundsInvalidate(int refresh) { Background *bg; ECORE_LIST_FOR_EACH(bg_list, bg) BackgroundInvalidate(bg, refresh); } static Background * BackgroundGetRandom(void) { Background *bg; int num; unsigned int rnd; num = ecore_list_count(bg_list); for (;;) { rnd = rand(); bg = (Background *) ecore_list_index_goto(bg_list, rnd % num); if (num <= 1 || !BackgroundIsNone(bg)) break; } return bg; } void BackgroundSetForDesk(Background * bg, unsigned int desk) { if (desk >= N_BG_ASSIGNED) return; bg_assigned[desk] = bg; } Background * BackgroundGetForDesk(unsigned int desk) { Background *bg; if (desk >= N_BG_ASSIGNED) return NULL; bg = bg_assigned[desk]; if (bg) bg = BackgroundCheck(bg); if (!bg) bg = BackgroundGetRandom(); return bg; } /* * Config load/save */ #include "conf.h" int BackgroundsConfigLoad(FILE * fs) { int err = 0; Background *bg = 0; unsigned int color; char s[FILEPATH_LEN_MAX]; char s2[FILEPATH_LEN_MAX]; int ii1; int r, g, b; int i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0; int j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0; char *bg1 = 0; char *bg2 = 0; char *name = 0; char ignore = 0; int desk; COLOR32_FROM_RGB(color, 0, 0, 0); while (GetLine(s, sizeof(s), fs)) { ii1 = ConfigParseline1(s, s2, NULL, NULL); switch (ii1) { case CONFIG_CLOSE: if (!ignore && !bg && name) bg = BackgroundCreate(name, color, bg1, i1, i2, i3, i4, i5, i6, bg2, j1, j2, j3, j4, j5); goto done; case CONFIG_COLORMOD: case ICLASS_COLORMOD: break; case CONFIG_CLASSNAME: case BG_NAME: bg = BackgroundFind(s2); if (bg) { ignore = 1; } else { Efree(name); name = Estrdup(s2); } break; case BG_DESKNUM: if (!ignore && !bg && name) bg = BackgroundCreate(name, color, bg1, i1, i2, i3, i4, i5, i6, bg2, j1, j2, j3, j4, j5); if (!bg) break; desk = atoi(s2); if (desk >= N_BG_ASSIGNED) break; if (desk >= 0) { if (!bg_assigned[desk] || Conf.backgrounds.user) { bg_assigned[desk] = bg; bg->referenced = 1; } } else { bg->referenced = 1; for (ii1 = 0; ii1 < N_BG_ASSIGNED; ii1++) { if (!bg_assigned[ii1]) bg_assigned[ii1] = bg; } } break; case BG_RGB: r = g = b = 0; sscanf(s, "%*s %d %d %d", &r, &g, &b); COLOR32_FROM_RGB(color, r, g, b); if (ignore) bg->bg_solid = color; break; case BG_BG1: sscanf(s, "%*s %4000s %d %d %d %d %d %d", s2, &i1, &i2, &i3, &i4, &i5, &i6); if (!ignore) { Efree(bg1); bg1 = Estrdup(s2); } else { Efree(bg->bg.file); Efree(bg->top.file); bg->top.file = NULL; bg->bg.file = Estrdup(s2); bg->bg_tile = i1; bg->bg.keep_aspect = i2; bg->bg.xjust = i3; bg->bg.yjust = i4; bg->bg.xperc = i5; bg->bg.yperc = i6; } break; case BG_BG2: sscanf(s, "%*s %4000s %d %d %d %d %d", s2, &j1, &j2, &j3, &j4, &j5); if (!ignore) { Efree(bg2); bg2 = Estrdup(s2); } else { bg->top.file = Estrdup(s2); bg->top.keep_aspect = j1; bg->top.xjust = j2; bg->top.yjust = j3; bg->top.xperc = j4; bg->top.yperc = j5; } break; default: break; } } err = -1; done: Efree(name); Efree(bg1); Efree(bg2); return err; } static void BackgroundsConfigLoadUser(void) { char s[4096]; Esnprintf(s, sizeof(s), "%s.backgrounds", EGetSavePrefix()); if (!exists(s)) Mode.backgrounds.force_scan = 1; ConfigFileLoad(s, NULL, ConfigFileRead, 0); } static void BackgroundsConfigSave(void) { char s[FILEPATH_LEN_MAX], st[FILEPATH_LEN_MAX]; FILE *fs; Background *bg; unsigned int j; int i, num, r, g, b; num = ecore_list_count(bg_list); if (num <= 0) return; Etmp(st); fs = fopen(st, "w"); if (!fs) return; for (i = num - 1; i >= 0; i--) { bg = (Background *) ecore_list_index_goto(bg_list, i); if (!bg) continue; fprintf(fs, "5 999\n"); fprintf(fs, "100 %s\n", bg->name); COLOR32_TO_RGB(bg->bg_solid, r, g, b); fprintf(fs, "560 %d %d %d\n", r, g, b); if ((bg->bg.file) && (!bg->bg.real_file)) bg->bg.real_file = ThemeFileFind(bg->bg.file); if ((bg->top.file) && (!bg->top.real_file)) bg->top.real_file = ThemeFileFind(bg->top.file); if ((bg->bg.file) && (bg->bg.real_file)) { fprintf(fs, "561 %s %d %d %d %d %d %d\n", bg->bg.real_file, bg->bg_tile, bg->bg.keep_aspect, bg->bg.xjust, bg->bg.yjust, bg->bg.xperc, bg->bg.yperc); } else if (bg->bg.file) { fprintf(fs, "561 %s %d %d %d %d %d %d\n", bg->bg.file, bg->bg_tile, bg->bg.keep_aspect, bg->bg.xjust, bg->bg.yjust, bg->bg.xperc, bg->bg.yperc); } if ((bg->top.file) && (bg->top.real_file)) { fprintf(fs, "562 %s %d %d %d %d %d\n", bg->top.real_file, bg->top.keep_aspect, bg->top.xjust, bg->top.yjust, bg->top.xperc, bg->top.yperc); } else if (bg->top.file) { fprintf(fs, "562 %s %d %d %d %d %d\n", bg->top.file, bg->top.keep_aspect, bg->top.xjust, bg->top.yjust, bg->top.xperc, bg->top.yperc); } for (j = 0; j < N_BG_ASSIGNED; j++) { if (bg == bg_assigned[j]) fprintf(fs, "564 %d\n", j); } fprintf(fs, "1000\n"); } fclose(fs); Esnprintf(s, sizeof(s), "%s.backgrounds", EGetSavePrefix()); E_mv(st, s); } /* * Backgrounds module */ static void BackgroundsCheckDups(void) { int ix; Background *bg, *bgx; for (ix = 0;; ix++) { ecore_list_index_goto(bg_list, ix); bg = (Background *) ecore_list_next(bg_list); if (!bg) break; for (; (bgx = (Background *) ecore_list_next(bg_list)) != NULL;) { if (bgx->ref_count > 0 || bgx->referenced) continue; if (BackgroundCmp(bg, bgx)) continue; #if 1 /* Remove? */ Eprintf("Remove duplicate background %s (==%s)\n", bgx->name, bg->name); #endif BackgroundDestroy(bgx); } } } static void BackgroundsAccounting(void) { Background *bg; time_t now; DesksBackgroundRefresh(NULL, DESK_BG_TIMEOUT); now = time(NULL); ECORE_LIST_FOR_EACH(bg_list, bg) { /* Skip if no pixmap or not timed out */ if (bg->pmap == None || ((now - bg->last_viewed) <= Conf.backgrounds.timeout)) continue; DesksBackgroundRefresh(bg, DESK_BG_FREE); BackgroundPixmapFree(bg); } } static int BackgroundsTimeout(void *data __UNUSED__) { if (Conf.backgrounds.timeout <= 0) Conf.backgrounds.timeout = 1; BackgroundsAccounting(); TimerSetInterval(bg_timer, 1.0 * Conf.backgrounds.timeout); return 1; } static void BackgroundsSighan(int sig, void *prm __UNUSED__) { switch (sig) { case ESIGNAL_INIT: EDirMake(EDirUserCache(), "cached/bgsel"); EDirMake(EDirUserCache(), "cached/img"); /* create a fallback background in case no background is found */ BackgroundCreate(NULL, 0, NULL, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0); break; case ESIGNAL_CONFIGURE: BackgroundsConfigLoadUser(); BackgroundsCheckDups(); StartupBackgroundsDestroy(); break; case ESIGNAL_START: TIMER_ADD(bg_timer, 30.0, BackgroundsTimeout, NULL); break; case ESIGNAL_EXIT: if (Mode.wm.save_ok) BackgroundsConfigSave(); break; } } #if ENABLE_DIALOGS /* * Configuration dialog */ static Dialog *bg_sel_dialog; static DItem *bg_sel; static DItem *bg_sel_slider; static DItem *bg_mini_disp; static DItem *bg_filename; static DItem *tmp_w[10]; static Background *tmp_bg; /* The background being configured */ static int tmp_bg_sel_sliderval; static int tmp_bg_sel_sliderval_old; static int tmp_bg_r; static int tmp_bg_g; static int tmp_bg_b; static char tmp_bg_image; static char tmp_bg_tile; static char tmp_bg_keep_aspect; static int tmp_bg_xjust; static int tmp_bg_yjust; static int tmp_bg_xperc; static int tmp_bg_yperc; static char tmp_hiq; static char tmp_userbg; static char tmp_root_hint; static int tmp_bg_timeout; static void BG_RedrawView(void); static void BGSettingsGoTo(Background * bg); static void CB_ConfigureBG(Dialog * d __UNUSED__, int val, void *data __UNUSED__) { if (val == 2) { bg_sel = bg_sel_slider = bg_mini_disp = bg_filename = NULL; memset(tmp_w, 0, sizeof(tmp_w)); BackgroundImagesKeep(tmp_bg, 0); tmp_bg = NULL; return; } if (val < 2) { Conf.backgrounds.timeout = tmp_bg_timeout; Conf.backgrounds.hiquality = tmp_hiq; Conf.backgrounds.user = tmp_userbg; Conf.hints.set_xroot_info_on_root_window = tmp_root_hint; COLOR32_FROM_RGB(tmp_bg->bg_solid, tmp_bg_r, tmp_bg_g, tmp_bg_b); tmp_bg->bg_tile = tmp_bg_tile; tmp_bg->bg.keep_aspect = tmp_bg_keep_aspect; tmp_bg->bg.xjust = tmp_bg_xjust; tmp_bg->bg.yjust = tmp_bg_yjust; tmp_bg->bg.xperc = tmp_bg_xperc; tmp_bg->bg.yperc = tmp_bg_yperc; if (!tmp_bg_image) BackgroundFilesRemove(tmp_bg); BackgroundInvalidate(tmp_bg, 1); BackgroundCacheMini(tmp_bg, 0, 1); BG_RedrawView(); } autosave(); } /* Draw the background preview image */ static void CB_DesktopMiniDisplayRedraw(Dialog * d __UNUSED__, int val __UNUSED__, void *data) { Background *bg; Pixmap pmap; int w, h; DItem *di; Win win; unsigned int color; const char *fbg, *ffg; if (!tmp_bg) return; di = (DItem *) data; win = DialogItemAreaGetWindow(di); DialogItemAreaGetSize(di, &w, &h); pmap = EGetWindowBackgroundPixmap(win); fbg = (tmp_bg_image) ? BackgroundGetBgFile(tmp_bg) : NULL; ffg = (tmp_bg_image) ? BackgroundGetFgFile(tmp_bg) : NULL; COLOR32_FROM_RGB(color, tmp_bg_r, tmp_bg_g, tmp_bg_b); bg = BackgroundCreate("TEMP", color, fbg, tmp_bg_tile, tmp_bg_keep_aspect, tmp_bg_xjust, tmp_bg_yjust, tmp_bg_xperc, tmp_bg_yperc, ffg, tmp_bg->top.keep_aspect, tmp_bg->top.xjust, tmp_bg->top.yjust, tmp_bg->top.xperc, tmp_bg->top.yperc); BackgroundApplyPmap(bg, win, pmap, w, h); BackgroundDestroy(bg); EClearWindow(win); } /* Update tmp vars according to the current tmp_bg */ static void BG_GetValues(void) { tmp_bg_image = (tmp_bg->bg.file) ? 1 : 0; COLOR32_TO_RGB(tmp_bg->bg_solid, tmp_bg_r, tmp_bg_g, tmp_bg_b); tmp_bg_tile = tmp_bg->bg_tile; tmp_bg_keep_aspect = tmp_bg->bg.keep_aspect; tmp_bg_xjust = tmp_bg->bg.xjust; tmp_bg_yjust = tmp_bg->bg.yjust; tmp_bg_xperc = tmp_bg->bg.xperc; tmp_bg_yperc = tmp_bg->bg.yperc; } static void BG_DialogSetFileName(DItem * di) { const char *stmp; char s[1024]; stmp = fullfileof(BackgroundGetBgFile(tmp_bg)); Esnprintf(s, sizeof(s), _("Background definition information:\nName: %s\nFile: %s\n"), BackgroundGetName(tmp_bg), (stmp) ? stmp : _("-NONE-")); DialogItemSetText(di, s); } static void BgDialogSetNewCurrent(Background * bg) { int i; if (tmp_bg && tmp_bg != bg) BackgroundImagesKeep(tmp_bg, 0); tmp_bg = bg; BackgroundImagesKeep(tmp_bg, 1); /* Fetch new BG values */ BG_GetValues(); /* Update dialog items */ BG_DialogSetFileName(bg_filename); DialogDrawItems(bg_sel_dialog, bg_filename, 0, 0, 99999, 99999); DialogItemCheckButtonSetState(tmp_w[0], tmp_bg_image); DialogItemCheckButtonSetState(tmp_w[1], tmp_bg_keep_aspect); DialogItemCheckButtonSetState(tmp_w[2], tmp_bg_tile); DialogItemSliderSetVal(tmp_w[3], tmp_bg_r); DialogItemSliderSetVal(tmp_w[4], tmp_bg_g); DialogItemSliderSetVal(tmp_w[5], tmp_bg_b); DialogItemSliderSetVal(tmp_w[6], tmp_bg_xjust); DialogItemSliderSetVal(tmp_w[7], tmp_bg_yjust); DialogItemSliderSetVal(tmp_w[8], tmp_bg_yperc); DialogItemSliderSetVal(tmp_w[9], tmp_bg_xperc); /* Redraw mini BG display */ CB_DesktopMiniDisplayRedraw(NULL, 0, bg_mini_disp); /* Redraw scrolling BG list */ BG_RedrawView(); for (i = 0; i < 10; i++) DialogDrawItems(bg_sel_dialog, tmp_w[i], 0, 0, 99999, 99999); } /* Duplicate current (tmp_bg) to new */ static void CB_ConfigureNewBG(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { char s[1024]; unsigned int color; int lower, upper; Esnprintf(s, sizeof(s), "__NEWBG_%i", (unsigned)time(NULL)); COLOR32_FROM_RGB(color, tmp_bg_r, tmp_bg_g, tmp_bg_b); tmp_bg = BackgroundCreate(s, color, tmp_bg->bg.file, tmp_bg_tile, tmp_bg_keep_aspect, tmp_bg_xjust, tmp_bg_yjust, tmp_bg_xperc, tmp_bg_yperc, tmp_bg->top.file, tmp_bg->top.keep_aspect, tmp_bg->top.xjust, tmp_bg->top.yjust, tmp_bg->top.xperc, tmp_bg->top.yperc); DialogItemSliderGetBounds(bg_sel_slider, &lower, &upper); upper += 4; DialogItemSliderSetBounds(bg_sel_slider, lower, upper); DialogItemSliderSetVal(bg_sel_slider, 0); DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999); DeskBackgroundSet(DesksGetCurrent(), tmp_bg); BG_RedrawView(); autosave(); } static void CB_ConfigureDelBG(Dialog * d __UNUSED__, int val, void *data __UNUSED__) { Background *bg; int i, num; int slider, lower, upper; num = ecore_list_count(bg_list); if (num <= 1) return; bg = (Background *) ecore_list_goto(bg_list, tmp_bg); if (!bg) return; i = ecore_list_index(bg_list); bg = (Background *) ecore_list_index_goto(bg_list, (i < num - 1) ? i + 1 : i - 1); DeskBackgroundSet(DesksGetCurrent(), bg); if (val == 0) BackgroundDestroy(tmp_bg); else BackgroundDelete(tmp_bg); tmp_bg = NULL; DialogItemSliderGetBounds(bg_sel_slider, &lower, &upper); slider = DialogItemSliderGetVal(bg_sel_slider); upper -= 4; DialogItemSliderSetBounds(bg_sel_slider, lower, upper); if (slider > upper) DialogItemSliderSetVal(bg_sel_slider, upper); BgDialogSetNewCurrent(bg); autosave(); } /* Move current background to first position in list */ static void CB_ConfigureFrontBG(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { ecore_list_prepend(bg_list, ecore_list_node_remove(bg_list, tmp_bg)); BGSettingsGoTo(tmp_bg); BG_RedrawView(); autosave(); } /* Draw the scrolling background image window */ static void BG_RedrawView(void) { Background *bg; int x, w, h, num; Win win; Pixmap pmap; ImageClass *ic_button; num = ecore_list_count(bg_list); if (num <= 0) return; win = DialogItemAreaGetWindow(bg_sel); DialogItemAreaGetSize(bg_sel, &w, &h); pmap = EGetWindowBackgroundPixmap(win); ic_button = ImageclassFind("DIALOG_BUTTON", 1); ImageclassApplySimple(ic_button, win, pmap, STATE_NORMAL, 0, 0, w, h); x = -(num * (64 + 8) - w) * tmp_bg_sel_sliderval / (4 * num); ECORE_LIST_FOR_EACH(bg_list, bg) { if (((x + 64 + 8) >= 0) && (x < w)) { EImage *im; ImageclassApplySimple(ic_button, win, pmap, (bg == tmp_bg) ? STATE_CLICKED : STATE_NORMAL, x, 0, 64 + 8, 48 + 8); if (BackgroundIsNone(bg)) { TextClass *tc; tc = TextclassFind("DIALOG", 1); if (tc) { int tw, th; TextSize(tc, 0, 0, STATE_NORMAL, _("No\nBackground"), &tw, &th, 17); TextDraw(tc, win, pmap, 0, 0, STATE_NORMAL, _("No\nBackground"), x + 4, 4 + ((48 - th) / 2), 64, 48, 17, 512); } } else { im = BackgroundCacheMini(bg, 1, 0); if (im) { EImageRenderOnDrawable(im, win, pmap, 0, x + 4, 4, 64, 48); EImageFree(im); } } } x += (64 + 8); } EClearWindow(win); } static void CB_BGAreaSlide(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { if (tmp_bg_sel_sliderval == tmp_bg_sel_sliderval_old) return; BG_RedrawView(); tmp_bg_sel_sliderval_old = tmp_bg_sel_sliderval; } static void CB_BGScan(Dialog * d, int val __UNUSED__, void *data __UNUSED__) { int num; SoundPlay(SOUND_WAIT); /* Forcing re-scan should not be necessary but provides the progress bars * so it actually looks like something is going on */ Mode.backgrounds.force_scan = 1; ScanBackgroundMenu(); num = ecore_list_count(bg_list); DialogItemSliderSetBounds(bg_sel_slider, 0, num * 4); DialogDrawItems(d, bg_sel_slider, 0, 0, 99999, 99999); DialogItemCallCallback(d, bg_sel_slider); } static void CB_BGAreaEvent(DItem * di __UNUSED__, int val __UNUSED__, void *data) { int x, num, w, h; Background *bg; XEvent *ev = (XEvent *) data; DialogItemAreaGetSize(bg_sel, &w, &h); switch (ev->type) { case ButtonPress: switch (ev->xbutton.button) { case 1: num = ecore_list_count(bg_list); x = (num * (64 + 8) - w) * tmp_bg_sel_sliderval / (4 * num) + ev->xbutton.x; bg = (Background *) ecore_list_index_goto(bg_list, x / (64 + 8)); if (!bg || bg == DeskBackgroundGet(DesksGetCurrent())) break; BgDialogSetNewCurrent(bg); DeskBackgroundSet(DesksGetCurrent(), bg); autosave(); break; case 4: tmp_bg_sel_sliderval += 4; goto do_slide; case 5: tmp_bg_sel_sliderval -= 4; goto do_slide; do_slide: DialogItemSliderSetVal(bg_sel_slider, tmp_bg_sel_sliderval); CB_BGAreaSlide(NULL, 0, NULL); DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999); break; } } } static void CB_DesktopTimeout(Dialog * d __UNUSED__, int val __UNUSED__, void *data) { DItem *di; char s[256]; di = (DItem *) data; Esnprintf(s, sizeof(s), _("Unused backgrounds freed after %2i:%02i:%02i"), tmp_bg_timeout / 3600, (tmp_bg_timeout / 60) - (60 * (tmp_bg_timeout / 3600)), (tmp_bg_timeout) - (60 * (tmp_bg_timeout / 60))); DialogItemSetText(di, s); DialogDrawItems(bg_sel_dialog, di, 0, 0, 99999, 99999); } static void BGSettingsGoTo(Background * bg) { int i, num; if (!bg_sel_slider) return; bg = (Background *) ecore_list_goto(bg_list, bg); if (!bg) return; i = ecore_list_index(bg_list); num = ecore_list_count(bg_list); i = ((4 * num + 20) * i) / num - 8; if (i < 0) i = 0; else if (i > 4 * num) i = 4 * num; DialogItemSliderSetVal(bg_sel_slider, i); DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999); BgDialogSetNewCurrent(bg); } static void CB_BGNext(Dialog * d __UNUSED__, int val, void *data __UNUSED__) { Background *bg; bg = (Background *) ecore_list_goto(bg_list, tmp_bg); if (!bg) return; bg = (Background *) ecore_list_index_goto(bg_list, ecore_list_index(bg_list) + val); if (!bg) return; BGSettingsGoTo(bg); DeskBackgroundSet(DesksGetCurrent(), bg); } static int BG_SortFileCompare(void *_bg1, void *_bg2) { Background *bg1 = (Background *) _bg1; Background *bg2 = (Background *) _bg2; const char *name1, *name2; /* return < 0 is b1 < b2 */ /* return > 0 is b1 > b2 */ /* return 0 is b1 == b2 */ name1 = BackgroundGetBgFile(bg1); name2 = BackgroundGetBgFile(bg2); if (name1 && name2) return strcmp(name1, name2); if (name1) return 1; if (name2) return -1; return (bg1 < bg2) ? -1 : 1; } static void CB_BGSortFile(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { Background **bglist; int i, num; bglist = (Background **) ecore_list_items_get(bg_list, &num); if (!bglist) return; /* remove them all from the list */ for (i = 0; i < num; i++) ecore_list_node_remove(bg_list, bglist[i]); Quicksort((void **)bglist, 0, num - 2, BG_SortFileCompare); for (i = 0; i < num; i++) ecore_list_append(bg_list, bglist[i]); Efree(bglist); BGSettingsGoTo(tmp_bg); autosave(); } static void CB_BGSortAttrib(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { Background **bglist; int i, num; bglist = (Background **) ecore_list_items_get(bg_list, &num); if (!bglist) return; /* remove them all from the list */ for (i = 0; i < num; i++) ecore_list_node_remove(bg_list, bglist[i]); for (i = 0; i < num; i++) { Background *bg; bg = bglist[i]; if ((bg) && (bg->bg_tile) && (bg->bg.xperc == 0) && (bg->bg.yperc == 0)) { ecore_list_prepend(bg_list, bg); bglist[i] = NULL; } } for (i = 0; i < num; i++) { Background *bg; bg = bglist[i]; if (bg) { ecore_list_prepend(bg_list, bg); bglist[i] = NULL; } } Efree(bglist); BGSettingsGoTo(tmp_bg); autosave(); } #if 0 /* Doesn't do anything useful */ static void CB_BGSortContent(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { Background **bglist; int i, num; bglist = (Background **) ecore_list_items_get(bg_list, &num); if (!bglist) return; /* remove them all from the list */ for (i = 0; i < num; i++) ecore_list_node_remove(bg_list, bglist[i]); for (i = 0; i < num; i++) ecore_list_prepend(bg_list, bglist[i]); Efree(bglist); autosave(); } #endif #if 0 /* Remove? */ static void CB_DesktopMiniDisplayAreaInit(DItem * di, int val __UNUSED__, void *data __UNUSED__) { CB_DesktopMiniDisplayRedraw(DialogItemGetDialog(di), 1, di); } #endif static void CB_InitView(DItem * di __UNUSED__, int val __UNUSED__, void *data __UNUSED__) { tmp_bg_sel_sliderval_old = tmp_bg_sel_sliderval = -1; BGSettingsGoTo(tmp_bg); } static void _DlgFillBackground(Dialog * d, DItem * table, void *data) { Background *bg = (Background *) data; DItem *di, *table2, *table3, *area, *label; int i, num; char s[1024]; if (!Conf.backgrounds.no_scan) ScanBackgroundMenu(); if (!bg) bg = DeskBackgroundGet(DesksGetCurrent()); if (!bg) bg = BackgroundFind("NONE"); tmp_bg = bg; BG_GetValues(); tmp_hiq = Conf.backgrounds.hiquality; tmp_userbg = Conf.backgrounds.user; tmp_root_hint = Conf.hints.set_xroot_info_on_root_window; tmp_bg_timeout = Conf.backgrounds.timeout; bg_sel_dialog = d; DialogItemTableSetOptions(table, 1, 0, 0, 0); table2 = DialogAddItem(table, DITEM_TABLE); DialogItemTableSetOptions(table2, 2, 0, 1, 0); di = bg_filename = DialogAddItem(table2, DITEM_TEXT); DialogItemSetFill(di, 1, 0); BG_DialogSetFileName(bg_filename); table3 = DialogAddItem(table2, DITEM_TABLE); di = tmp_w[0] = DialogAddItem(table3, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Use background image")); DialogItemCheckButtonSetPtr(di, &tmp_bg_image); di = tmp_w[1] = DialogAddItem(table3, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Keep aspect on scale")); DialogItemCheckButtonSetPtr(di, &tmp_bg_keep_aspect); di = tmp_w[2] = DialogAddItem(table3, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Tile image across background")); DialogItemCheckButtonSetPtr(di, &tmp_bg_tile); table2 = DialogAddItem(table, DITEM_TABLE); DialogItemTableSetOptions(table2, 4, 0, 1, 0); DialogItemSetFill(table2, 0, 0); DialogItemSetAlign(table2, 512, 0); di = DialogAddItem(table2, DITEM_BUTTON); DialogItemSetText(di, _("Move to Front\n")); DialogItemSetCallback(di, CB_ConfigureFrontBG, 0, NULL); DialogBindKey(d, "F", CB_ConfigureFrontBG, 0, NULL); di = DialogAddItem(table2, DITEM_BUTTON); DialogItemSetText(di, _("Duplicate\n")); DialogItemSetCallback(di, CB_ConfigureNewBG, 0, NULL); di = DialogAddItem(table2, DITEM_BUTTON); DialogItemSetText(di, _("Unlist\n")); DialogItemSetCallback(di, CB_ConfigureDelBG, 0, NULL); DialogBindKey(d, "D", CB_ConfigureDelBG, 0, NULL); di = DialogAddItem(table2, DITEM_BUTTON); DialogItemSetText(di, _("Delete File\n")); DialogItemSetCallback(di, CB_ConfigureDelBG, 1, NULL); DialogBindKey(d, "Delete", CB_ConfigureDelBG, 1, NULL); table2 = DialogAddItem(table, DITEM_TABLE); DialogItemTableSetOptions(table2, 3, 0, 1, 0); di = DialogAddItem(table2, DITEM_TEXT); DialogItemSetFill(di, 0, 0); DialogItemSetAlign(di, 512, 512); DialogItemSetText(di, _("Background\n" "Image\n" "Scaling\n" "and\n" "Alignment\n")); table3 = DialogAddItem(table2, DITEM_TABLE); DialogItemTableSetOptions(table3, 3, 0, 0, 0); di = DialogAddItem(table3, DITEM_NONE); di = tmp_w[6] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetMinLength(di, 10); DialogItemSliderSetBounds(di, 0, 1024); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 64); DialogItemSliderSetValPtr(di, &tmp_bg_xjust); di = DialogAddItem(table3, DITEM_NONE); di = tmp_w[7] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetMinLength(di, 10); DialogItemSliderSetOrientation(di, 0); DialogItemSetFill(di, 0, 1); DialogItemSliderSetBounds(di, 0, 1024); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 64); DialogItemSliderSetValPtr(di, &tmp_bg_yjust); di = bg_mini_disp = area = DialogAddItem(table3, DITEM_AREA); DialogItemAreaSetSize(di, 64, 48); #if 0 /* Remove? */ DialogItemAreaSetInitFunc(di, CB_DesktopMiniDisplayAreaInit); #endif di = tmp_w[8] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetMinLength(di, 10); DialogItemSliderSetOrientation(di, 0); DialogItemSetFill(di, 0, 1); DialogItemSliderSetBounds(di, 0, 1024); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 64); DialogItemSliderSetValPtr(di, &tmp_bg_yperc); di = DialogAddItem(table3, DITEM_NONE); di = tmp_w[9] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetMinLength(di, 10); DialogItemSliderSetBounds(di, 0, 1024); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 64); DialogItemSliderSetValPtr(di, &tmp_bg_xperc); table3 = DialogAddItem(table2, DITEM_TABLE); DialogItemTableSetOptions(table3, 2, 0, 0, 0); di = DialogAddItem(table3, DITEM_TEXT); DialogItemSetColSpan(di, 2); DialogItemSetFill(di, 0, 0); DialogItemSetAlign(di, 512, 512); DialogItemSetText(di, _("BG Colour\n")); di = DialogAddItem(table3, DITEM_TEXT); DialogItemSetFill(di, 0, 0); DialogItemSetAlign(di, 1024, 512); DialogItemSetText(di, _("Red:\n")); di = tmp_w[3] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetBounds(di, 0, 255); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 16); DialogItemSliderSetValPtr(di, &tmp_bg_r); di = DialogAddItem(table3, DITEM_TEXT); DialogItemSetFill(di, 0, 0); DialogItemSetAlign(di, 1024, 512); DialogItemSetText(di, _("Green:\n")); di = tmp_w[4] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetBounds(di, 0, 255); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 16); DialogItemSliderSetValPtr(di, &tmp_bg_g); di = DialogAddItem(table3, DITEM_TEXT); DialogItemSetFill(di, 0, 0); DialogItemSetAlign(di, 1024, 512); DialogItemSetText(di, _("Blue:\n")); di = tmp_w[5] = DialogAddItem(table3, DITEM_SLIDER); DialogItemSliderSetBounds(di, 0, 255); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 16); DialogItemSliderSetValPtr(di, &tmp_bg_b); for (i = 0; i < 10; i++) DialogItemSetCallback(tmp_w[i], CB_DesktopMiniDisplayRedraw, 0, area); di = DialogAddItem(table, DITEM_SEPARATOR); table2 = DialogAddItem(table, DITEM_TABLE); DialogItemTableSetOptions(table2, 3, 0, 0, 0); table3 = DialogAddItem(table2, DITEM_TABLE); DialogItemTableSetOptions(table3, 2, 0, 0, 0); di = DialogAddItem(table3, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, "<-"); DialogItemSetCallback(di, CB_BGNext, -1, NULL); DialogBindKey(d, "Left", CB_BGNext, -1, NULL); di = DialogAddItem(table3, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, "->"); DialogItemSetCallback(di, CB_BGNext, 1, NULL); DialogBindKey(d, "Right", CB_BGNext, 1, NULL); di = DialogAddItem(table2, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, _("Pre-scan BG's")); DialogItemSetCallback(di, CB_BGScan, 0, NULL); table3 = DialogAddItem(table2, DITEM_TABLE); DialogItemTableSetOptions(table3, 3, 0, 0, 0); di = DialogAddItem(table3, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, _("Sort by File")); DialogItemSetCallback(di, CB_BGSortFile, 0, NULL); di = DialogAddItem(table3, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, _("Sort by Attr.")); DialogItemSetCallback(di, CB_BGSortAttrib, 0, NULL); #if 0 /* Doesn't do anything useful */ di = DialogAddItem(table3, DITEM_BUTTON); DialogItemSetFill(di, 0, 0); DialogItemSetText(di, _("Sort by Image")); DialogItemSetCallback(di, CB_BGSortContent, 0, NULL); #endif di = bg_sel = DialogAddItem(table, DITEM_AREA); DialogItemAreaSetSize(di, 160, 56); DialogItemAreaSetEventFunc(di, CB_BGAreaEvent); DialogItemAreaSetInitFunc(di, CB_InitView); num = ecore_list_count(bg_list); di = bg_sel_slider = DialogAddItem(table, DITEM_SLIDER); DialogItemSliderSetBounds(di, 0, num * 4); DialogItemSliderSetUnits(di, 1); DialogItemSliderSetJump(di, 9); DialogItemSliderSetValPtr(di, &tmp_bg_sel_sliderval); DialogItemSetCallback(bg_sel_slider, CB_BGAreaSlide, 0, NULL); di = DialogAddItem(table, DITEM_SEPARATOR); di = DialogAddItem(table, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Use dithering in Hi-Colour")); DialogItemCheckButtonSetPtr(di, &tmp_hiq); di = DialogAddItem(table, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Background overrides theme")); DialogItemCheckButtonSetPtr(di, &tmp_userbg); di = DialogAddItem(table, DITEM_CHECKBUTTON); DialogItemSetText(di, _("Enable background transparency compatibility mode")); DialogItemCheckButtonSetPtr(di, &tmp_root_hint); di = DialogAddItem(table, DITEM_SEPARATOR); di = label = DialogAddItem(table, DITEM_TEXT); DialogItemSetAlign(di, 512, 512); Esnprintf(s, sizeof(s), _("Unused backgrounds freed after %2i:%02i:%02i"), tmp_bg_timeout / 3600, (tmp_bg_timeout / 60) - (60 * (tmp_bg_timeout / 3600)), (tmp_bg_timeout) - (60 * (tmp_bg_timeout / 60))); DialogItemSetText(di, s); di = DialogAddItem(table, DITEM_SLIDER); DialogItemSliderSetMinLength(di, 10); DialogItemSliderSetBounds(di, 0, 60 * 60 * 4); DialogItemSliderSetUnits(di, 30); DialogItemSliderSetJump(di, 60); DialogItemSliderSetValPtr(di, &tmp_bg_timeout); DialogItemSetCallback(di, CB_DesktopTimeout, 0, label); } const DialogDef DlgBackground = { "CONFIGURE_BG", N_("Background"), N_("Desktop Background Settings"), SOUND_SETTINGS_BG, "pix/bg.png", N_("Enlightenment Desktop\n" "Background Settings Dialog\n"), _DlgFillBackground, DLG_OAC, CB_ConfigureBG, }; #endif /* ENABLE_DIALOGS */ /* * IPC functions */ static void BackgroundSet1(const char *name, const char *params) { const char *p = params; char type[FILEPATH_LEN_MAX]; int len, value; Background *bg; unsigned int color; if (!p || !p[0]) return; bg = BackgroundFind(name); if (!bg) { COLOR32_FROM_RGB(color, 0, 0, 0); bg = BackgroundCreate(name, color, NULL, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0); if (!bg) { IpcPrintf("Error: could not create background '%s'\n", name); return; } } type[0] = '\0'; len = 0; sscanf(p, "%400s %n", type, &len); p += len; value = atoi(p); if (!strcmp(type, "bg.solid")) { int r, b, g; r = g = b = 0; sscanf(p, "%i %i %i", &r, &g, &b); COLOR32_FROM_RGB(bg->bg_solid, r, g, b); } else if (!strcmp(type, "bg.file")) { Efree(bg->bg.file); bg->bg.file = Estrdup(p); } else if (!strcmp(type, "bg.tile")) { bg->bg_tile = value; } else if (!strcmp(type, "bg.keep_aspect")) { bg->bg.keep_aspect = value; } else if (!strcmp(type, "bg.xjust")) { bg->bg.xjust = value; } else if (!strcmp(type, "bg.yjust")) { bg->bg.yjust = value; } else if (!strcmp(type, "bg.xperc")) { bg->bg.xperc = value; } else if (!strcmp(type, "bg.yperc")) { bg->bg.yperc = value; } else if (!strcmp(type, "top.file")) { Efree(bg->top.file); bg->top.file = Estrdup(p); } else if (!strcmp(type, "top.keep_aspect")) { bg->top.keep_aspect = value; } else if (!strcmp(type, "top.xjust")) { bg->top.xjust = value; } else if (!strcmp(type, "top.yjust")) { bg->top.yjust = value; } else if (!strcmp(type, "top.xperc")) { bg->top.xperc = value; } else if (!strcmp(type, "top.yperc")) { bg->top.yperc = value; } else { IpcPrintf("Error: unknown background value type '%s'\n", type); } autosave(); } static void BackgroundSet2(const char *name, const char *params) { Background *bg; unsigned int color; unsigned int i; int r, g, b; char bgf[FILEPATH_LEN_MAX], topf[FILEPATH_LEN_MAX]; int tile, keep_aspect, tkeep_aspect; int xjust, yjust, xperc, yperc; int txjust, tyjust, txperc, typerc; if (params == NULL) return; bgf[0] = topf[0] = '\0'; r = g = b = 99; i = sscanf(params, "%i %i %i %4000s %i %i %i %i %i %i %4000s %i %i %i %i %i", &r, &g, &b, bgf, &tile, &keep_aspect, &xjust, &yjust, &xperc, &yperc, topf, &tkeep_aspect, &txjust, &tyjust, &txperc, &typerc); COLOR32_FROM_RGB(color, r, g, b); bg = BackgroundFind(name); if (bg) { BackgroundModify(bg, color, bgf, tile, keep_aspect, xjust, yjust, xperc, yperc, topf, tkeep_aspect, txjust, tyjust, txperc, typerc); } else { bg = BackgroundCreate(name, color, bgf, tile, keep_aspect, xjust, yjust, xperc, yperc, topf, tkeep_aspect, txjust, tyjust, txperc, typerc); } } static void BackgroundsIpc(const char *params) { const char *p; char cmd[128], prm[128], buf[4096]; int i, len, num, len2; Background *bg; len = len2 = 0; cmd[0] = prm[0] = '\0'; p = params; if (p) { sscanf(p, "%100s %n%100s %n", cmd, &len2, prm, &len); p += len; } if (!p || cmd[0] == '?') { for (i = 0; i < (int)DesksGetNumber(); i++) { bg = DeskBackgroundGet(DeskGet(i)); if (bg) IpcPrintf("%i %s\n", i, BackgroundGetName(bg)); else IpcPrintf("%i %s\n", i, "-NONE-"); } } else if (!strncmp(cmd, "apply", 2)) { Window xwin; Win win; bg = BackgroundFind(prm); if (!bg) return; xwin = None; sscanf(p, "%lx", &xwin); win = ECreateWinFromXwin(xwin); if (!win) return; BackgroundApplyWin(bg, win); EDestroyWin(win); } else if (!strncmp(cmd, "del", 2)) { BackgroundDestroyByName(prm); } else if (!strncmp(cmd, "list", 2)) { ECORE_LIST_FOR_EACH(bg_list, bg) IpcPrintf("%s\n", bg->name); } else if (!strncmp(cmd, "load", 2)) { bg = BackgroundFind(prm); if (bg) { IpcPrintf("Background already defined\n"); } else { bg = BrackgroundCreateFromImage(prm, p, NULL, 0); } } else if (!strncmp(cmd, "set", 2)) { BackgroundSet1(prm, p); } else if (!strncmp(cmd, "show", 2)) { bg = BackgroundFind(prm); if (bg) { BackgroundGetInfoString1(bg, buf, sizeof(buf)); IpcPrintf("%s\n", buf); } else IpcPrintf("Error: background '%s' does not exist\n", prm); } else if (!strcmp(cmd, "use")) { if (!strcmp(prm, "-")) bg = NULL; else bg = BackgroundFind(prm); num = DesksGetCurrentNum(); sscanf(p, "%d %n", &num, &len); DeskBackgroundSet(DeskGet(num), bg); autosave(); } else if (!strncmp(cmd, "xget", 2)) { bg = BackgroundFind(prm); if (bg) { BackgroundGetInfoString2(bg, buf, sizeof(buf)); IpcPrintf("%s\n", buf); } else IpcPrintf("Error: background '%s' does not exist\n", prm); } else if (!strncmp(cmd, "xset", 2)) { BackgroundSet2(prm, p); } else { /* Compatibility with pre- 0.16.8 clients */ BackgroundSet1(cmd, params + len2); } } static void IPC_BackgroundUse(const char *params) { char name[1024]; const char *p; Background *bg; int i, l; p = params; name[0] = '\0'; l = 0; sscanf(p, "%1000s %n", name, &l); p += l; bg = BackgroundFind(name); if (!bg) return; for (;;) { i = l = -1; sscanf(p, "%d %n", &i, &l); p += l; if (i < 0) break; DeskBackgroundSet(DeskGet(i), bg); } autosave(); } static const IpcItem BackgroundsIpcArray[] = { { BackgroundsIpc, "background", "bg", "Background commands", " background Show current background\n" " background apply Apply background to window\n" " background del Delete background\n" " background list Show all background\n" " background load Load new wallpaper from file\n" " background set ... Set background parameters\n" " background show Show background info\n" " background use Switch to background \n" " background xget Special show background parameters\n" " background xset ... Special set background parameters\n"} , { IPC_BackgroundUse, "use_bg", NULL, "Deprecated - do not use", NULL} , }; #define N_IPC_FUNCS (sizeof(BackgroundsIpcArray)/sizeof(IpcItem)) /* * Configuration items */ static const CfgItem BackgroundsCfgItems[] = { CFG_ITEM_BOOL(Conf.backgrounds, hiquality, 1), CFG_ITEM_BOOL(Conf.backgrounds, user, 1), CFG_ITEM_BOOL(Conf.backgrounds, no_scan, 0), CFG_ITEM_INT(Conf.backgrounds, timeout, 240), }; #define N_CFG_ITEMS (sizeof(BackgroundsCfgItems)/sizeof(CfgItem)) /* * Module descriptor */ extern const EModule ModBackgrounds; const EModule ModBackgrounds = { "backgrounds", "bg", BackgroundsSighan, {N_IPC_FUNCS, BackgroundsIpcArray}, {N_CFG_ITEMS, BackgroundsCfgItems} };