chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / backgrounds.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2009 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <time.h>
25 #include "E.h"
26 #include "backgrounds.h"
27 #include "desktops.h"
28 #include "dialog.h"
29 #include "e16-ecore_list.h"
30 #include "eimage.h"
31 #include "emodule.h"
32 #include "file.h"
33 #include "iclass.h"
34 #include "settings.h"
35 #include "tclass.h"
36 #include "timers.h"
37 #include "xwin.h"
38
39 typedef struct {
40    char               *file;
41    char               *real_file;
42    EImage             *im;
43    char                keep_aspect;
44    int                 xjust, yjust;
45    int                 xperc, yperc;
46 } BgPart;
47
48 struct _background {
49    char               *name;
50    Pixmap              pmap;
51    time_t              last_viewed;
52    EColor              bg_solid;
53    char                bg_tile;
54    BgPart              bg;
55    BgPart              top;
56    char                external;
57    char                keepim;
58    char                referenced;
59    unsigned int        ref_count;
60    unsigned int        seq_no;
61 };
62
63 static Ecore_List  *bg_list = NULL;
64 static Timer       *bg_timer = NULL;
65 static unsigned int bg_seq_no = 0;
66
67 #define N_BG_ASSIGNED 32
68 static Background  *bg_assigned[N_BG_ASSIGNED];
69
70 char               *
71 BackgroundGetUniqueString(const Background * bg)
72 {
73    char                s[256];
74    const char         *chmap =
75       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
76    int                 r, g, b;
77    int                 n1, n2, n3, n4, n5, f1, f2, f3, f4, f5, f6;
78
79    GET_COLOR(&(bg->bg_solid), r, g, b);
80    n1 = (r << 24) | (g << 16) | (b << 8) | (bg->bg_tile << 7)
81       | (bg->bg.keep_aspect << 6) | (bg->top.keep_aspect << 5);
82    n2 = (bg->bg.xjust << 16) | (bg->bg.yjust);
83    n3 = (bg->bg.xperc << 16) | (bg->bg.yperc);
84    n4 = (bg->top.xjust << 16) | (bg->top.yjust);
85    n5 = (bg->top.xperc << 16) | (bg->top.yperc);
86    f1 = 0;
87    f2 = 0;
88    f3 = 0;
89    f4 = 0;
90    f5 = 0;
91    f6 = 0;
92    if (bg->bg.file)
93      {
94         char               *f;
95
96         f = ThemeFileFind(bg->bg.file);
97         if (f)
98           {
99              f1 = fileinode(f);
100              f2 = filedev(f);
101              f3 = (int)moddate(f);
102              Efree(f);
103           }
104      }
105    if (bg->top.file)
106      {
107         char               *f;
108
109         f = ThemeFileFind(bg->top.file);
110         if (f)
111           {
112              f4 = fileinode(f);
113              f5 = filedev(f);
114              f6 = (int)moddate(f);
115              Efree(f);
116           }
117      }
118    Esnprintf(s, sizeof(s),
119              "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c"
120              "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c"
121              "%c%c%c%c%c%c" "%c%c%c%c%c%c" "%c%c%c%c%c%c",
122              chmap[(n1 >> 0) & 0x3f], chmap[(n1 >> 6) & 0x3f],
123              chmap[(n1 >> 12) & 0x3f], chmap[(n1 >> 18) & 0x3f],
124              chmap[(n1 >> 24) & 0x3f], chmap[(n1 >> 28) & 0x3f],
125              chmap[(n2 >> 0) & 0x3f], chmap[(n2 >> 6) & 0x3f],
126              chmap[(n2 >> 12) & 0x3f], chmap[(n2 >> 18) & 0x3f],
127              chmap[(n2 >> 24) & 0x3f], chmap[(n2 >> 28) & 0x3f],
128              chmap[(n3 >> 0) & 0x3f], chmap[(n3 >> 6) & 0x3f],
129              chmap[(n3 >> 12) & 0x3f], chmap[(n3 >> 18) & 0x3f],
130              chmap[(n3 >> 24) & 0x3f], chmap[(n3 >> 28) & 0x3f],
131              chmap[(n4 >> 0) & 0x3f], chmap[(n4 >> 6) & 0x3f],
132              chmap[(n4 >> 12) & 0x3f], chmap[(n4 >> 18) & 0x3f],
133              chmap[(n4 >> 24) & 0x3f], chmap[(n4 >> 28) & 0x3f],
134              chmap[(n5 >> 0) & 0x3f], chmap[(n5 >> 6) & 0x3f],
135              chmap[(n5 >> 12) & 0x3f], chmap[(n5 >> 18) & 0x3f],
136              chmap[(n5 >> 24) & 0x3f], chmap[(n5 >> 28) & 0x3f],
137              chmap[(f1 >> 0) & 0x3f], chmap[(f1 >> 6) & 0x3f],
138              chmap[(f1 >> 12) & 0x3f], chmap[(f1 >> 18) & 0x3f],
139              chmap[(f1 >> 24) & 0x3f], chmap[(f1 >> 28) & 0x3f],
140              chmap[(f2 >> 0) & 0x3f], chmap[(f2 >> 6) & 0x3f],
141              chmap[(f2 >> 12) & 0x3f], chmap[(f2 >> 18) & 0x3f],
142              chmap[(f2 >> 24) & 0x3f], chmap[(f2 >> 28) & 0x3f],
143              chmap[(f3 >> 0) & 0x3f], chmap[(f3 >> 6) & 0x3f],
144              chmap[(f3 >> 12) & 0x3f], chmap[(f3 >> 18) & 0x3f],
145              chmap[(f3 >> 24) & 0x3f], chmap[(f3 >> 28) & 0x3f],
146              chmap[(f4 >> 0) & 0x3f], chmap[(f4 >> 6) & 0x3f],
147              chmap[(f4 >> 12) & 0x3f], chmap[(f4 >> 18) & 0x3f],
148              chmap[(f4 >> 24) & 0x3f], chmap[(f4 >> 28) & 0x3f],
149              chmap[(f5 >> 0) & 0x3f], chmap[(f5 >> 6) & 0x3f],
150              chmap[(f5 >> 12) & 0x3f], chmap[(f5 >> 18) & 0x3f],
151              chmap[(f5 >> 24) & 0x3f], chmap[(f5 >> 28) & 0x3f],
152              chmap[(f6 >> 0) & 0x3f], chmap[(f6 >> 6) & 0x3f],
153              chmap[(f6 >> 12) & 0x3f], chmap[(f6 >> 18) & 0x3f],
154              chmap[(f6 >> 24) & 0x3f], chmap[(f6 >> 28) & 0x3f]);
155    return Estrdup(s);
156 }
157
158 void
159 BackgroundPixmapSet(Background * bg, Pixmap pmap)
160 {
161    if (bg->pmap != None && bg->pmap != pmap)
162       Eprintf("*** BackgroundPixmapSet %s: pmap was set %#lx/%#lx\n",
163               bg->name, bg->pmap, pmap);
164    bg->pmap = pmap;
165 }
166
167 static void
168 BackgroundPixmapFree(Background * bg)
169 {
170    if (bg->pmap)
171      {
172         EImagePixmapsFree(bg->pmap, None);
173         bg->pmap = None;
174      }
175 }
176
177 static void
178 BackgroundImagesFree(Background * bg)
179 {
180    if (bg->bg.im)
181      {
182         EImageFree(bg->bg.im);
183         bg->bg.im = NULL;
184      }
185    if (bg->top.im)
186      {
187         EImageFree(bg->top.im);
188         bg->top.im = NULL;
189      }
190 }
191
192 #if ENABLE_DIALOGS
193 static void
194 BackgroundImagesKeep(Background * bg, int onoff)
195 {
196    if (onoff)
197      {
198         bg->keepim = 1;
199      }
200    else
201      {
202         bg->keepim = 0;
203         BackgroundImagesFree(bg);
204      }
205 }
206 #endif /* ENABLE_DIALOGS */
207
208 static void
209 BackgroundFilesRemove(Background * bg)
210 {
211    Efree(bg->bg.file);
212    bg->bg.file = NULL;
213
214    Efree(bg->bg.real_file);
215    bg->bg.real_file = NULL;
216
217    Efree(bg->top.file);
218    bg->top.file = NULL;
219
220    Efree(bg->top.real_file);
221    bg->top.real_file = NULL;
222
223    BackgroundImagesFree(bg);
224
225    bg->keepim = 0;
226 }
227
228 static int
229 BackgroundDestroy(Background * bg)
230 {
231    if (!bg)
232       return -1;
233
234    if (bg->ref_count > 0)
235      {
236         DialogOK("Background Error!", _("%u references remain\n"),
237                  bg->ref_count);
238         return -1;
239      }
240
241    ecore_list_node_remove(bg_list, bg);
242
243    BackgroundFilesRemove(bg);
244    BackgroundPixmapFree(bg);
245
246    Efree(bg->name);
247
248    Efree(bg);
249
250    return 0;
251 }
252
253 #if ENABLE_DIALOGS
254 static void
255 BackgroundDelete(Background * bg)
256 {
257    char               *f;
258
259    if (BackgroundDestroy(bg))
260       return;
261
262    /* And delete the actual image files */
263    if (bg->bg.file)
264      {
265         f = ThemeFileFind(bg->bg.file);
266         if (f)
267           {
268              E_rm(f);
269              Efree(f);
270           }
271      }
272    if (bg->top.file)
273      {
274         f = ThemeFileFind(bg->top.file);
275         if (f)
276           {
277              E_rm(f);
278              Efree(f);
279           }
280      }
281 }
282 #endif /* ENABLE_DIALOGS */
283
284 static Background  *
285 BackgroundCreate(const char *name, EColor * solid, const char *bgn, char tile,
286                  char keep_aspect, int xjust, int yjust, int xperc,
287                  int yperc, const char *top, char tkeep_aspect, int txjust,
288                  int tyjust, int txperc, int typerc)
289 {
290    Background         *bg;
291
292    bg = ECALLOC(Background, 1);
293    if (!bg)
294       return NULL;
295
296    bg->name = Estrdup(name);
297
298    SET_COLOR(&(bg->bg_solid), 160, 160, 160);
299    if (solid)
300       bg->bg_solid = *solid;
301    else
302       bg->external = 1;
303    if (bgn)
304       bg->bg.file = Estrdup(bgn);
305    bg->bg_tile = tile;
306    bg->bg.keep_aspect = keep_aspect;
307    bg->bg.xjust = xjust;
308    bg->bg.yjust = yjust;
309    bg->bg.xperc = xperc;
310    bg->bg.yperc = yperc;
311
312    if (top)
313       bg->top.file = Estrdup(top);
314    bg->top.keep_aspect = tkeep_aspect;
315    bg->top.xjust = txjust;
316    bg->top.yjust = tyjust;
317    bg->top.xperc = txperc;
318    bg->top.yperc = typerc;
319
320    bg->seq_no = ++bg_seq_no;
321
322    if (!bg_list)
323       bg_list = ecore_list_new();
324    ecore_list_prepend(bg_list, bg);
325
326    return bg;
327 }
328
329 static int
330 BackgroundCmp(Background * bg, Background * bgx)
331 {
332    if (*bgx->name != '.')       /* Discard only generated backgrounds */
333       return 1;
334
335    if (bg->bg.file && bgx->bg.file)
336      {
337         if ((strcmp(bg->bg.file, bgx->bg.file)) ||
338             (bg->bg.keep_aspect != bgx->bg.keep_aspect) ||
339             (bg->bg.xjust != bgx->bg.xjust || bg->bg.xjust != bgx->bg.xjust) ||
340             (bg->bg.xperc != bgx->bg.xperc || bg->bg.xperc != bgx->bg.xperc))
341            return 1;
342      }
343    else if (bg->bg.file || bgx->bg.file)
344       return 1;
345
346    if (bg->top.file && bgx->top.file)
347      {
348         if ((strcmp(bg->top.file, bgx->top.file)) ||
349             (bg->top.keep_aspect != bgx->top.keep_aspect) ||
350             (bg->top.xjust != bgx->top.xjust ||
351              bg->top.xjust != bgx->top.xjust) ||
352             (bg->top.xperc != bgx->top.xperc ||
353              bg->top.xperc != bgx->top.xperc))
354            return 1;
355      }
356    else if (bg->top.file || bgx->top.file)
357       return 1;
358
359    if ((bg->bg_solid.red != bgx->bg_solid.red) ||
360        (bg->bg_solid.green != bgx->bg_solid.green) ||
361        (bg->bg_solid.blue != bgx->bg_solid.blue))
362       return 1;
363    if (bg->bg_tile != bgx->bg_tile)
364       return 1;
365
366    return 0;
367 }
368
369 static int
370 _BackgroundMatchName(const void *data, const void *match)
371 {
372    return strcmp(((const Background *)data)->name, (const char *)match);
373 }
374
375 Background         *
376 BackgroundFind(const char *name)
377 {
378    return (Background *) ecore_list_find(bg_list, _BackgroundMatchName, name);
379 }
380
381 static Background  *
382 BackgroundCheck(Background * bg)
383 {
384    return (Background *) ecore_list_goto(bg_list, bg);
385 }
386
387 void
388 BackgroundDestroyByName(const char *name)
389 {
390    BackgroundDestroy(BackgroundFind(name));
391 }
392
393 static void
394 BackgroundInvalidate(Background * bg, int refresh)
395 {
396    BackgroundPixmapFree(bg);
397    bg->seq_no = ++bg_seq_no;
398    if (bg->ref_count && refresh)
399       DesksBackgroundRefresh(bg, DESK_BG_REFRESH);
400 }
401
402 static int
403 BackgroundModify(Background * bg, EColor * solid, const char *bgn, char tile,
404                  char keep_aspect, int xjust, int yjust, int xperc,
405                  int yperc, const char *top, char tkeep_aspect, int txjust,
406                  int tyjust, int txperc, int typerc)
407 {
408    int                 updated = 0;
409
410    if (solid->red != bg->bg_solid.red)
411       updated = 1;
412    if (solid->green != bg->bg_solid.green)
413       updated = 1;
414    if (solid->blue != bg->bg_solid.blue)
415       updated = 1;
416    bg->bg_solid = *solid;
417
418    if ((bg->bg.file) && (bgn))
419      {
420         if (strcmp(bg->bg.file, bgn))
421            updated = 1;
422      }
423    else
424       updated = 1;
425    Efree(bg->bg.file);
426    bg->bg.file = (bgn[0]) ? Estrdup(bgn) : NULL;
427    if ((int)tile != bg->bg_tile)
428       updated = 1;
429    if ((int)keep_aspect != bg->bg.keep_aspect)
430       updated = 1;
431    if (xjust != bg->bg.xjust)
432       updated = 1;
433    if (yjust != bg->bg.yjust)
434       updated = 1;
435    if (xperc != bg->bg.xperc)
436       updated = 1;
437    if (yperc != bg->bg.yperc)
438       updated = 1;
439    bg->bg_tile = (char)tile;
440    bg->bg.keep_aspect = (char)keep_aspect;
441    bg->bg.xjust = xjust;
442    bg->bg.yjust = yjust;
443    bg->bg.xperc = xperc;
444    bg->bg.yperc = yperc;
445
446    if ((bg->top.file) && (top))
447      {
448         if (strcmp(bg->top.file, top))
449            updated = 1;
450      }
451    else
452       updated = 1;
453    Efree(bg->top.file);
454    bg->top.file = (top[0]) ? Estrdup(top) : NULL;
455    if ((int)tkeep_aspect != bg->top.keep_aspect)
456       updated = 1;
457    if (txjust != bg->top.xjust)
458       updated = 1;
459    if (tyjust != bg->top.yjust)
460       updated = 1;
461    if (txperc != bg->top.xperc)
462       updated = 1;
463    if (typerc != bg->top.yperc)
464       updated = 1;
465    bg->top.keep_aspect = (char)tkeep_aspect;
466    bg->top.xjust = txjust;
467    bg->top.yjust = tyjust;
468    bg->top.xperc = txperc;
469    bg->top.yperc = typerc;
470
471    if (updated)
472       BackgroundInvalidate(bg, 1);
473
474    return updated;
475 }
476
477 static void
478 BgFindImageSize(BgPart * bgp, unsigned int rw, unsigned int rh,
479                 unsigned int *pw, unsigned int *ph)
480 {
481    int                 w, h, iw, ih;
482
483    EImageGetSize(bgp->im, &iw, &ih);
484
485 #if 0                           /* FIXME - Remove? */
486    if (bgp->keep_aspect)
487       bgp->xperc = bgp->yperc;
488 #endif
489
490    if (bgp->xperc > 0)
491       w = (rw * bgp->xperc) >> 10;
492    else
493       w = (iw * rw) / WinGetW(VROOT);
494
495    if (bgp->yperc > 0)
496       h = (rh * bgp->yperc) >> 10;
497    else
498       h = (ih * rh) / WinGetH(VROOT);
499
500    if (w <= 0)
501       w = 1;
502    if (h <= 0)
503       h = 1;
504
505    if (bgp->keep_aspect)
506      {
507         if (bgp->yperc <= 0)
508           {
509              if (((w << 10) / h) != ((iw << 10) / ih))
510                 h = ((w * ih) / iw);
511           }
512         else
513           {
514              if (((h << 10) / w) != ((ih << 10) / iw))
515                 w = ((h * iw) / ih);
516           }
517      }
518
519    *pw = (unsigned int)w;
520    *ph = (unsigned int)h;
521 }
522
523 static              Pixmap
524 BackgroundCreatePixmap(Win win, unsigned int w, unsigned int h)
525 {
526    Pixmap              pmap;
527
528    /*
529     * Stupid hack to avoid that a new root pixmap has the same ID as the now
530     * invalid one from a previous session.
531     */
532    pmap = ECreatePixmap(win, w, h, 0);
533    if (win == RROOT && pmap == Mode.root.ext_pmap)
534      {
535         EFreePixmap(pmap);
536         pmap = ECreatePixmap(win, w, h, 0);
537         Mode.root.ext_pmap = None;
538         Mode.root.ext_pmap_valid = 0;
539      }
540    return pmap;
541 }
542
543 void
544 BackgroundRealize(Background * bg, Win win, Drawable draw, unsigned int rw,
545                   unsigned int rh, int is_win, Pixmap * ppmap,
546                   unsigned long *ppixel)
547 {
548    Pixmap              pmap;
549    GC                  gc;
550    int                 x, y, ww, hh;
551    unsigned int        w, h;
552    char                hasbg, hasfg;
553    EImage             *im;
554
555    if (bg->bg.file && !bg->bg.im)
556      {
557         if (!bg->bg.real_file)
558            bg->bg.real_file = ThemeFileFind(bg->bg.file);
559         if (bg->bg.real_file)
560            bg->bg.im = EImageLoad(bg->bg.real_file);
561      }
562
563    if (bg->top.file && !bg->top.im)
564      {
565         if (!bg->top.real_file)
566            bg->top.real_file = ThemeFileFind(bg->top.file);
567         if (bg->top.real_file)
568            bg->top.im = EImageLoad(bg->top.real_file);
569      }
570
571    if (!draw)
572       draw = WinGetXwin(win);
573
574    hasbg = bg->bg.im != NULL;
575    hasfg = bg->top.im != NULL;
576
577    if (!hasbg && !hasfg)
578      {
579         /* Solid color only */
580         EAllocColor(WinGetCmap(VROOT), &bg->bg_solid);
581
582         if (!is_win)
583           {
584              gc = EXCreateGC(draw, 0, NULL);
585              XSetClipMask(disp, gc, 0);
586              XSetFillStyle(disp, gc, FillSolid);
587              XSetForeground(disp, gc, bg->bg_solid.pixel);
588              XFillRectangle(disp, draw, gc, 0, 0, rw, rh);
589              EXFreeGC(gc);
590           }
591         if (ppmap)
592            *ppmap = None;
593         if (ppixel)
594            *ppixel = bg->bg_solid.pixel;
595         return;
596      }
597
598    /* Has either bg or fg image */
599
600    w = h = x = y = 0;
601
602    if (hasbg)
603      {
604         BgFindImageSize(&(bg->bg), rw, rh, &w, &h);
605         x = ((int)(rw - w) * bg->bg.xjust) >> 10;
606         y = ((int)(rh - h) * bg->bg.yjust) >> 10;
607      }
608
609    if (is_win && hasbg && !hasfg && x == 0 && y == 0 &&
610        ((w == rw && h == rh) || (bg->bg_tile && !TransparencyEnabled())))
611      {
612         /* Window, no fg, no offset, and scale to 100%, or tiled, no trans */
613         pmap = BackgroundCreatePixmap(win, w, h);
614         EImageRenderOnDrawable(bg->bg.im, win, pmap, EIMAGE_ANTI_ALIAS,
615                                0, 0, w, h);
616
617 #if 0                           /* FIXME - Remove? */
618         if (x == 0 && y == 0)   /* Hmmm. Always true. */
619           {
620              ESetWindowBackgroundPixmap(draw, pmap);
621           }
622         else
623           {
624              gc = EXCreateGC(draw, 0, NULL);
625              XSetTile(disp, gc, pmap);
626              XSetTSOrigin(disp, gc, x, y);
627              XSetFillStyle(disp, gc, FillTiled);
628              XFillRectangle(disp, draw, gc, 0, 0, rw, rh);
629              EXFreeGC(gc);
630           }
631 #endif
632         goto done;
633      }
634
635    /* The rest that require some more work */
636    if (is_win)
637       pmap = BackgroundCreatePixmap(win, rw, rh);
638    else
639       pmap = draw;
640
641    if (hasbg && !hasfg && x == 0 && y == 0 && w == rw && h == rh)
642      {
643         im = bg->bg.im;
644      }
645    else
646      {
647         /* Create full size image */
648         im = EImageCreate(rw, rh);
649         EImageSetHasAlpha(im, 0);
650         if (!hasbg || !bg->bg_tile)
651           {
652              /* Fill solid */
653              EImageFill(im, 0, 0, rw, rh, bg->bg_solid.red, bg->bg_solid.green,
654                         bg->bg_solid.blue, 255);
655           }
656         if (hasbg)
657           {
658              if (bg->bg_tile)
659                {
660                   EImageTile(im, bg->bg.im, 0, w, h, 0, 0, rw, rh, x, y);
661                }
662              else
663                {
664                   EImageGetSize(bg->bg.im, &ww, &hh);
665                   EImageBlend(im, bg->bg.im, EIMAGE_ANTI_ALIAS, 0, 0, ww, hh,
666                               x, y, w, h, 1);
667                }
668           }
669      }
670
671    if (hasfg)
672      {
673         EImageGetSize(bg->top.im, &ww, &hh);
674
675         BgFindImageSize(&(bg->top), rw, rh, &w, &h);
676         x = ((rw - w) * bg->top.xjust) >> 10;
677         y = ((rh - h) * bg->top.yjust) >> 10;
678
679         EImageBlend(im, bg->top.im, EIMAGE_BLEND | EIMAGE_ANTI_ALIAS,
680                     0, 0, ww, hh, x, y, w, h, 0);
681      }
682
683    EImageRenderOnDrawable(im, win, pmap, EIMAGE_ANTI_ALIAS, 0, 0, rw, rh);
684    if (im != bg->bg.im)
685       EImageFree(im);
686
687  done:
688    if (!bg->keepim)
689       BackgroundImagesFree(bg);
690
691    if (ppmap)
692       *ppmap = pmap;
693    if (ppixel)
694       *ppixel = 0;
695 }
696
697 void
698 BackgroundApplyPmap(Background * bg, Win win, Drawable draw,
699                     unsigned int w, unsigned int h)
700 {
701    BackgroundRealize(bg, win, draw, w, h, 0, NULL, NULL);
702 }
703
704 static void
705 BackgroundApplyWin(Background * bg, Win win)
706 {
707    int                 w, h;
708    Pixmap              pmap;
709    unsigned long       pixel;
710
711    if (!EGetGeometry(win, NULL, NULL, NULL, &w, &h, NULL, NULL))
712       return;
713
714    BackgroundRealize(bg, win, None, w, h, 1, &pmap, &pixel);
715    if (pmap != None)
716      {
717         ESetWindowBackgroundPixmap(win, pmap);
718         EImagePixmapsFree(pmap, None);
719      }
720    else
721      {
722         ESetWindowBackground(win, pixel);
723      }
724    EClearWindow(win);
725 }
726
727 /*
728  * Apply a background to window.
729  * The BG pixmap is stored in bg->pmap.
730  */
731 void
732 BackgroundSet(Background * bg, Win win, unsigned int w, unsigned int h)
733 {
734    Pixmap              pmap = None;
735    unsigned long       pixel = 0;
736
737    if (bg->pmap)
738       pmap = bg->pmap;
739    else
740       BackgroundRealize(bg, win, None, w, h, 1, &pmap, &pixel);
741
742    bg->pmap = pmap;
743    if (pmap != None)
744       ESetWindowBackgroundPixmap(win, pmap);
745    else
746       ESetWindowBackground(win, pixel);
747    EClearWindow(win);
748 }
749
750 Background         *
751 BrackgroundCreateFromImage(const char *bgid, const char *file,
752                            char *thumb, int thlen)
753 {
754    Background         *bg;
755    EImage             *im, *im2;
756    EColor              color;
757    char                tile = 1, keep_asp = 0;
758    int                 width, height;
759    int                 scalex = 0, scaley = 0;
760    int                 scr_asp, im_asp;
761    int                 w2, h2;
762    int                 maxw = 48, maxh = 48;
763    int                 justx = 512, justy = 512;
764
765    bg = BackgroundFind(bgid);
766
767    if (thumb)
768      {
769         Esnprintf(thumb, thlen, "%s/cached/img/%s.png", EDirUserCache(), bgid);
770         if (bg && exists(thumb) && moddate(thumb) > moddate(file))
771            return bg;
772         /* The thumbnail is gone or outdated - regererate */
773      }
774    else
775      {
776         if (bg)
777            return bg;
778      }
779
780    im = EImageLoad(file);
781    if (!im)
782       return NULL;
783
784    EImageGetSize(im, &width, &height);
785
786    if (thumb)
787      {
788         h2 = maxh;
789         w2 = (width * h2) / height;
790         if (w2 > maxw)
791           {
792              w2 = maxw;
793              h2 = (height * w2) / width;
794           }
795         im2 = EImageCreateScaled(im, 0, 0, width, height, w2, h2);
796         EImageSave(im2, thumb);
797         EImageDecache(im2);
798      }
799
800    EImageDecache(im);
801
802    /* Quit if the background itself already exists */
803    if (bg)
804       return bg;
805
806    scr_asp = (WinGetW(VROOT) << 16) / WinGetH(VROOT);
807    im_asp = (width << 16) / height;
808    if (width == height)
809      {
810         justx = 0;
811         justy = 0;
812         scalex = 0;
813         scaley = 0;
814         tile = 1;
815         keep_asp = 0;
816      }
817    else if ((!(IN_RANGE(scr_asp, im_asp, 16000)))
818             && ((width < 480) && (height < 360)))
819      {
820         justx = 0;
821         justy = 0;
822         scalex = 0;
823         scaley = 0;
824         tile = 1;
825         keep_asp = 0;
826      }
827    else if (IN_RANGE(scr_asp, im_asp, 16000))
828      {
829         justx = 0;
830         justy = 0;
831         scalex = 1024;
832         scaley = 1024;
833         tile = 0;
834         keep_asp = 0;
835      }
836    else if (im_asp > scr_asp)
837      {
838         justx = 512;
839         justy = 512;
840         scalex = 1024;
841         scaley = 0;
842         tile = 0;
843         keep_asp = 1;
844      }
845    else
846      {
847         justx = 512;
848         justy = 512;
849         scalex = 0;
850         scaley = 1024;
851         tile = 0;
852         keep_asp = 1;
853      }
854
855    SET_COLOR(&color, 0, 0, 0);
856
857    bg = BackgroundCreate(bgid, &color, file, tile,
858                          keep_asp, justx, justy,
859                          scalex, scaley, NULL, 0, 0, 0, 0, 0);
860
861    return bg;
862 }
863
864 void
865 BackgroundIncRefcount(Background * bg)
866 {
867    if (bg == NULL)
868       return;
869    bg->ref_count++;
870 }
871
872 void
873 BackgroundDecRefcount(Background * bg)
874 {
875    if (bg == NULL)
876       return;
877    bg->ref_count--;
878    if (bg->ref_count <= 0)
879       bg->last_viewed = 0;      /* Clean out asap */
880 }
881
882 void
883 BackgroundTouch(Background * bg)
884 {
885    if (bg == NULL)
886       return;
887    bg->last_viewed = time(NULL);
888 }
889
890 const char         *
891 BackgroundGetName(const Background * bg)
892 {
893    return bg->name;
894 }
895
896 #if ENABLE_DIALOGS
897 static const char  *
898 BackgroundGetBgFile(const Background * bg)
899 {
900    return bg->bg.file;
901 }
902
903 static const char  *
904 BackgroundGetFgFile(const Background * bg)
905 {
906    return bg->top.file;
907 }
908 #endif /* ENABLE_DIALOGS */
909
910 Pixmap
911 BackgroundGetPixmap(const Background * bg)
912 {
913    return (bg) ? bg->pmap : None;
914 }
915
916 unsigned int
917 BackgroundGetSeqNo(const Background * bg)
918 {
919    return bg->seq_no;
920 }
921
922 int
923 BackgroundIsNone(const Background * bg)
924 {
925    return (bg) ? bg->external : 1;
926 }
927
928 #if ENABLE_DIALOGS
929 static EImage      *
930 BackgroundCacheMini(Background * bg, int keep, int nuke)
931 {
932    char                s[4096];
933    EImage             *im;
934    Pixmap              pmap;
935
936    Esnprintf(s, sizeof(s), "%s/cached/bgsel/%s.png", EDirUserCache(),
937              BackgroundGetName(bg));
938
939    im = EImageLoad(s);
940    if (im)
941      {
942         if (nuke)
943            EImageDecache(im);
944         else
945            goto done;
946      }
947
948    /* Create new cached bg mini image */
949    pmap = ECreatePixmap(VROOT, 64, 48, 0);
950    BackgroundApplyPmap(bg, VROOT, pmap, 64, 48);
951    im = EImageGrabDrawable(pmap, None, 0, 0, 64, 48, 0);
952    EImageSave(im, s);
953    EFreePixmap(pmap);
954
955  done:
956    if (keep)
957       return im;
958    EImageFree(im);
959    return NULL;
960 }
961 #endif /* ENABLE_DIALOGS */
962
963 #define S(str) ((str) ? str : "(null)")
964 static void
965 BackgroundGetInfoString1(const Background * bg, char *buf, int len)
966 {
967    int                 r, g, b;
968
969    GET_COLOR(&(bg->bg_solid), r, g, b);
970    Esnprintf(buf, len,
971              "%s ref_count %u keepim %u\n"
972              " bg.solid\t %i %i %i \n"
973              " bg.file\t %s\n"
974              " top.file\t %s \n"
975              " bg.tile\t %i \n"
976              " bg.keep_aspect\t %i \ttop.keep_aspect\t %i \n"
977              " bg.xjust\t %i \ttop.xjust\t %i \n"
978              " bg.yjust\t %i \ttop.yjust\t %i \n"
979              " bg.xperc\t %i \ttop.xperc\t %i \n"
980              " bg.yperc\t %i \ttop.yperc\t %i \n", bg->name,
981              bg->ref_count, bg->keepim, r, g, b,
982              bg->bg.file, bg->top.file, bg->bg_tile,
983              bg->bg.keep_aspect, bg->top.keep_aspect,
984              bg->bg.xjust, bg->top.xjust, bg->bg.yjust,
985              bg->top.yjust, bg->bg.xperc, bg->top.xperc,
986              bg->bg.yperc, bg->top.yperc);
987 }
988
989 static void
990 BackgroundGetInfoString2(const Background * bg, char *buf, int len)
991 {
992    int                 r, g, b;
993
994    GET_COLOR(&(bg->bg_solid), r, g, b);
995    Esnprintf(buf, len,
996              "%s %i %i %i %s %i %i %i %i %i %i %s %i %i %i %i %i",
997              bg->name, r, g, b, S(bg->bg.file), bg->bg_tile,
998              bg->bg.keep_aspect, bg->bg.xjust, bg->bg.yjust,
999              bg->bg.xperc, bg->bg.yperc, S(bg->top.file),
1000              bg->top.keep_aspect, bg->top.xjust, bg->top.yjust,
1001              bg->top.xperc, bg->top.yperc);
1002 }
1003
1004 void
1005 BackgroundsInvalidate(int refresh)
1006 {
1007    Background         *bg;
1008
1009    ECORE_LIST_FOR_EACH(bg_list, bg) BackgroundInvalidate(bg, refresh);
1010 }
1011
1012 static Background  *
1013 BackgroundGetRandom(void)
1014 {
1015    Background         *bg;
1016    int                 num;
1017    unsigned int        rnd;
1018
1019    num = ecore_list_count(bg_list);
1020    for (;;)
1021      {
1022         rnd = rand();
1023         bg = (Background *) ecore_list_index_goto(bg_list, rnd % num);
1024         if (num <= 1 || !BackgroundIsNone(bg))
1025            break;
1026      }
1027
1028    return bg;
1029 }
1030
1031 void
1032 BackgroundSetForDesk(Background * bg, unsigned int desk)
1033 {
1034    if (desk >= N_BG_ASSIGNED)
1035       return;
1036
1037    bg_assigned[desk] = bg;
1038 }
1039
1040 Background         *
1041 BackgroundGetForDesk(unsigned int desk)
1042 {
1043    Background         *bg;
1044
1045    if (desk >= N_BG_ASSIGNED)
1046       return NULL;
1047
1048    bg = bg_assigned[desk];
1049    if (bg)
1050       bg = BackgroundCheck(bg);
1051    if (!bg)
1052       bg = BackgroundGetRandom();
1053
1054    return bg;
1055 }
1056
1057 /*
1058  * Config load/save
1059  */
1060 #include "conf.h"
1061
1062 int
1063 BackgroundsConfigLoad(FILE * fs)
1064 {
1065    int                 err = 0;
1066    Background         *bg = 0;
1067    EColor              color;
1068    char                s[FILEPATH_LEN_MAX];
1069    char                s2[FILEPATH_LEN_MAX];
1070    int                 ii1;
1071    int                 r, g, b;
1072    int                 i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
1073    int                 j1 = 0, j2 = 0, j3 = 0, j4 = 0, j5 = 0;
1074    char               *bg1 = 0;
1075    char               *bg2 = 0;
1076    char               *name = 0;
1077    char                ignore = 0;
1078    int                 desk;
1079
1080    SET_COLOR(&color, 0, 0, 0);
1081
1082    while (GetLine(s, sizeof(s), fs))
1083      {
1084         ii1 = ConfigParseline1(s, s2, NULL, NULL);
1085         switch (ii1)
1086           {
1087           case CONFIG_CLOSE:
1088              if (!ignore && !bg && name)
1089                 bg = BackgroundCreate(name, &color, bg1, i1, i2, i3, i4, i5,
1090                                       i6, bg2, j1, j2, j3, j4, j5);
1091              goto done;
1092
1093           case CONFIG_COLORMOD:
1094           case ICLASS_COLORMOD:
1095              break;
1096
1097           case CONFIG_CLASSNAME:
1098           case BG_NAME:
1099              bg = BackgroundFind(s2);
1100              if (bg)
1101                {
1102                   ignore = 1;
1103                }
1104              else
1105                {
1106                   Efree(name);
1107                   name = Estrdup(s2);
1108                }
1109              break;
1110
1111           case BG_DESKNUM:
1112              if (!ignore && !bg && name)
1113                 bg = BackgroundCreate(name, &color, bg1, i1, i2, i3, i4, i5,
1114                                       i6, bg2, j1, j2, j3, j4, j5);
1115              if (!bg)
1116                 break;
1117              desk = atoi(s2);
1118              if (desk >= N_BG_ASSIGNED)
1119                 break;
1120              if (desk >= 0)
1121                {
1122                   if (!bg_assigned[desk] || Conf.backgrounds.user)
1123                     {
1124                        bg_assigned[desk] = bg;
1125                        bg->referenced = 1;
1126                     }
1127                }
1128              else
1129                {
1130                   bg->referenced = 1;
1131                   for (ii1 = 0; ii1 < N_BG_ASSIGNED; ii1++)
1132                     {
1133                        if (!bg_assigned[ii1])
1134                           bg_assigned[ii1] = bg;
1135                     }
1136                }
1137              break;
1138
1139           case BG_RGB:
1140              r = g = b = 0;
1141              sscanf(s, "%*s %d %d %d", &r, &g, &b);
1142              SET_COLOR(&color, r, g, b);
1143              if (ignore)
1144                 bg->bg_solid = color;
1145              break;
1146
1147           case BG_BG1:
1148              sscanf(s, "%*s %4000s %d %d %d %d %d %d", s2, &i1, &i2,
1149                     &i3, &i4, &i5, &i6);
1150              if (!ignore)
1151                {
1152                   Efree(bg1);
1153                   bg1 = Estrdup(s2);
1154                }
1155              else
1156                {
1157                   Efree(bg->bg.file);
1158                   Efree(bg->top.file);
1159                   bg->top.file = NULL;
1160                   bg->bg.file = Estrdup(s2);
1161                   bg->bg_tile = i1;
1162                   bg->bg.keep_aspect = i2;
1163                   bg->bg.xjust = i3;
1164                   bg->bg.yjust = i4;
1165                   bg->bg.xperc = i5;
1166                   bg->bg.yperc = i6;
1167                }
1168              break;
1169
1170           case BG_BG2:
1171              sscanf(s, "%*s %4000s %d %d %d %d %d", s2, &j1, &j2, &j3,
1172                     &j4, &j5);
1173              if (!ignore)
1174                {
1175                   Efree(bg2);
1176                   bg2 = Estrdup(s2);
1177                }
1178              else
1179                {
1180                   bg->top.file = Estrdup(s2);
1181                   bg->top.keep_aspect = j1;
1182                   bg->top.xjust = j2;
1183                   bg->top.yjust = j3;
1184                   bg->top.xperc = j4;
1185                   bg->top.yperc = j5;
1186                }
1187              break;
1188
1189           default:
1190              break;
1191           }
1192      }
1193    err = -1;
1194
1195  done:
1196    Efree(name);
1197    Efree(bg1);
1198    Efree(bg2);
1199
1200    return err;
1201 }
1202
1203 static void
1204 BackgroundsConfigLoadUser(void)
1205 {
1206    char                s[4096];
1207
1208    Esnprintf(s, sizeof(s), "%s.backgrounds", EGetSavePrefix());
1209    if (!exists(s))
1210       Mode.backgrounds.force_scan = 1;
1211    ConfigFileLoad(s, NULL, ConfigFileRead, 0);
1212 }
1213
1214 static void
1215 BackgroundsConfigSave(void)
1216 {
1217    char                s[FILEPATH_LEN_MAX], st[FILEPATH_LEN_MAX];
1218    FILE               *fs;
1219    Background         *bg;
1220    unsigned int        j;
1221    int                 i, num, r, g, b;
1222
1223    num = ecore_list_count(bg_list);
1224    if (num <= 0)
1225       return;
1226
1227    Etmp(st);
1228    fs = fopen(st, "w");
1229    if (!fs)
1230       return;
1231
1232    for (i = num - 1; i >= 0; i--)
1233      {
1234         bg = (Background *) ecore_list_index_goto(bg_list, i);
1235         if (!bg)
1236            continue;
1237
1238         fprintf(fs, "5 999\n");
1239
1240         fprintf(fs, "100 %s\n", bg->name);
1241         GET_COLOR(&(bg->bg_solid), r, g, b);
1242         fprintf(fs, "560 %d %d %d\n", r, g, b);
1243
1244         if ((bg->bg.file) && (!bg->bg.real_file))
1245            bg->bg.real_file = ThemeFileFind(bg->bg.file);
1246
1247         if ((bg->top.file) && (!bg->top.real_file))
1248            bg->top.real_file = ThemeFileFind(bg->top.file);
1249
1250         if ((bg->bg.file) && (bg->bg.real_file))
1251           {
1252              fprintf(fs, "561 %s %d %d %d %d %d %d\n",
1253                      bg->bg.real_file, bg->bg_tile,
1254                      bg->bg.keep_aspect, bg->bg.xjust,
1255                      bg->bg.yjust, bg->bg.xperc, bg->bg.yperc);
1256           }
1257         else if (bg->bg.file)
1258           {
1259              fprintf(fs, "561 %s %d %d %d %d %d %d\n",
1260                      bg->bg.file, bg->bg_tile,
1261                      bg->bg.keep_aspect, bg->bg.xjust,
1262                      bg->bg.yjust, bg->bg.xperc, bg->bg.yperc);
1263           }
1264
1265         if ((bg->top.file) && (bg->top.real_file))
1266           {
1267              fprintf(fs, "562 %s %d %d %d %d %d\n",
1268                      bg->top.real_file,
1269                      bg->top.keep_aspect, bg->top.xjust,
1270                      bg->top.yjust, bg->top.xperc, bg->top.yperc);
1271           }
1272         else if (bg->top.file)
1273           {
1274              fprintf(fs, "562 %s %d %d %d %d %d\n",
1275                      bg->top.file, bg->top.keep_aspect,
1276                      bg->top.xjust, bg->top.yjust, bg->top.xperc,
1277                      bg->top.yperc);
1278           }
1279
1280         for (j = 0; j < N_BG_ASSIGNED; j++)
1281           {
1282              if (bg == bg_assigned[j])
1283                 fprintf(fs, "564 %d\n", j);
1284           }
1285
1286         fprintf(fs, "1000\n");
1287      }
1288
1289    fclose(fs);
1290
1291    Esnprintf(s, sizeof(s), "%s.backgrounds", EGetSavePrefix());
1292    E_mv(st, s);
1293 }
1294
1295 /*
1296  * Backgrounds module
1297  */
1298
1299 static void
1300 BackgroundsCheckDups(void)
1301 {
1302    int                 ix;
1303    Background         *bg, *bgx;
1304
1305    for (ix = 0;; ix++)
1306      {
1307         ecore_list_index_goto(bg_list, ix);
1308         bg = (Background *) ecore_list_next(bg_list);
1309         if (!bg)
1310            break;
1311         for (; (bgx = (Background *) ecore_list_next(bg_list)) != NULL;)
1312           {
1313              if (bgx->ref_count > 0 || bgx->referenced)
1314                 continue;
1315
1316              if (BackgroundCmp(bg, bgx))
1317                 continue;
1318 #if 1                           /* Remove? */
1319              Eprintf("Remove duplicate background %s (==%s)\n", bgx->name,
1320                      bg->name);
1321 #endif
1322              BackgroundDestroy(bgx);
1323           }
1324      }
1325 }
1326
1327 static void
1328 BackgroundsAccounting(void)
1329 {
1330    Background         *bg;
1331    time_t              now;
1332
1333    DesksBackgroundRefresh(NULL, DESK_BG_TIMEOUT);
1334
1335    now = time(NULL);
1336    ECORE_LIST_FOR_EACH(bg_list, bg)
1337    {
1338       /* Skip if no pixmap or not timed out */
1339       if (bg->pmap == None ||
1340           ((now - bg->last_viewed) <= Conf.backgrounds.timeout))
1341          continue;
1342
1343       DesksBackgroundRefresh(bg, DESK_BG_FREE);
1344       BackgroundPixmapFree(bg);
1345    }
1346 }
1347
1348 static int
1349 BackgroundsTimeout(void *data __UNUSED__)
1350 {
1351    if (Conf.backgrounds.timeout <= 0)
1352       Conf.backgrounds.timeout = 1;
1353
1354    BackgroundsAccounting();
1355
1356    TimerSetInterval(bg_timer, 1.0 * Conf.backgrounds.timeout);
1357
1358    return 1;
1359 }
1360
1361 static void
1362 BackgroundsSighan(int sig, void *prm __UNUSED__)
1363 {
1364    switch (sig)
1365      {
1366      case ESIGNAL_INIT:
1367         EDirMake(EDirUserCache(), "cached/bgsel");
1368         EDirMake(EDirUserCache(), "cached/img");
1369         /* create a fallback background in case no background is found */
1370         BackgroundCreate("NONE", NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, 0, 0, 0, 0,
1371                          0);
1372         break;
1373
1374      case ESIGNAL_CONFIGURE:
1375         BackgroundsConfigLoadUser();
1376         BackgroundsCheckDups();
1377         StartupBackgroundsDestroy();
1378         break;
1379
1380      case ESIGNAL_START:
1381         TIMER_ADD(bg_timer, 30.0, BackgroundsTimeout, NULL);
1382         break;
1383
1384      case ESIGNAL_EXIT:
1385         if (Mode.wm.save_ok)
1386            BackgroundsConfigSave();
1387         break;
1388      }
1389 }
1390
1391 #if ENABLE_DIALOGS
1392 /*
1393  * Configuration dialog
1394  */
1395 static Dialog      *bg_sel_dialog;
1396 static DItem       *bg_sel;
1397 static DItem       *bg_sel_slider;
1398 static DItem       *bg_mini_disp;
1399 static DItem       *bg_filename;
1400 static DItem       *tmp_w[10];
1401
1402 static Background  *tmp_bg;     /* The background being configured */
1403 static int          tmp_bg_sel_sliderval;
1404 static int          tmp_bg_sel_sliderval_old;
1405 static int          tmp_bg_r;
1406 static int          tmp_bg_g;
1407 static int          tmp_bg_b;
1408 static char         tmp_bg_image;
1409 static char         tmp_bg_tile;
1410 static char         tmp_bg_keep_aspect;
1411 static int          tmp_bg_xjust;
1412 static int          tmp_bg_yjust;
1413 static int          tmp_bg_xperc;
1414 static int          tmp_bg_yperc;
1415 static char         tmp_hiq;
1416 static char         tmp_userbg;
1417 static char         tmp_root_hint;
1418 static int          tmp_bg_timeout;
1419
1420 static void         BG_RedrawView(void);
1421 static void         BGSettingsGoTo(Background * bg);
1422
1423 static void
1424 CB_ConfigureBG(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
1425 {
1426    if (val == 2)
1427      {
1428         bg_sel = bg_sel_slider = bg_mini_disp = bg_filename = NULL;
1429         memset(tmp_w, 0, sizeof(tmp_w));
1430         BackgroundImagesKeep(tmp_bg, 0);
1431         tmp_bg = NULL;
1432         return;
1433      }
1434
1435    if (val < 2)
1436      {
1437         Conf.backgrounds.timeout = tmp_bg_timeout;
1438         Conf.backgrounds.hiquality = tmp_hiq;
1439         Conf.backgrounds.user = tmp_userbg;
1440         Conf.hints.set_xroot_info_on_root_window = tmp_root_hint;
1441
1442         SET_COLOR(&(tmp_bg->bg_solid), tmp_bg_r, tmp_bg_g, tmp_bg_b);
1443         tmp_bg->bg_tile = tmp_bg_tile;
1444         tmp_bg->bg.keep_aspect = tmp_bg_keep_aspect;
1445         tmp_bg->bg.xjust = tmp_bg_xjust;
1446         tmp_bg->bg.yjust = tmp_bg_yjust;
1447         tmp_bg->bg.xperc = tmp_bg_xperc;
1448         tmp_bg->bg.yperc = tmp_bg_yperc;
1449         if (!tmp_bg_image)
1450            BackgroundFilesRemove(tmp_bg);
1451
1452         BackgroundInvalidate(tmp_bg, 1);
1453
1454         BackgroundCacheMini(tmp_bg, 0, 1);
1455         BG_RedrawView();
1456      }
1457
1458    autosave();
1459 }
1460
1461 /* Draw the background preview image */
1462 static void
1463 CB_DesktopMiniDisplayRedraw(Dialog * d __UNUSED__, int val __UNUSED__,
1464                             void *data)
1465 {
1466    Background         *bg;
1467    Pixmap              pmap;
1468    int                 w, h;
1469    DItem              *di;
1470    Win                 win;
1471    EColor              color;
1472    const char         *fbg, *ffg;
1473
1474    if (!tmp_bg)
1475       return;
1476
1477    di = (DItem *) data;
1478    win = DialogItemAreaGetWindow(di);
1479    DialogItemAreaGetSize(di, &w, &h);
1480
1481    pmap = EGetWindowBackgroundPixmap(win);
1482    fbg = (tmp_bg_image) ? BackgroundGetBgFile(tmp_bg) : NULL;
1483    ffg = (tmp_bg_image) ? BackgroundGetFgFile(tmp_bg) : NULL;
1484    SET_COLOR(&color, tmp_bg_r, tmp_bg_g, tmp_bg_b);
1485    bg = BackgroundCreate("TEMP", &color,
1486                          fbg, tmp_bg_tile, tmp_bg_keep_aspect,
1487                          tmp_bg_xjust, tmp_bg_yjust,
1488                          tmp_bg_xperc, tmp_bg_yperc,
1489                          ffg, tmp_bg->top.keep_aspect,
1490                          tmp_bg->top.xjust, tmp_bg->top.yjust,
1491                          tmp_bg->top.xperc, tmp_bg->top.yperc);
1492
1493    BackgroundApplyPmap(bg, win, pmap, w, h);
1494    BackgroundDestroy(bg);
1495    EClearWindow(win);
1496 }
1497
1498 /* Update tmp vars according to the current tmp_bg */
1499 static void
1500 BG_GetValues(void)
1501 {
1502    tmp_bg_image = (tmp_bg->bg.file) ? 1 : 0;
1503
1504    GET_COLOR(&(tmp_bg->bg_solid), tmp_bg_r, tmp_bg_g, tmp_bg_b);
1505    tmp_bg_tile = tmp_bg->bg_tile;
1506    tmp_bg_keep_aspect = tmp_bg->bg.keep_aspect;
1507    tmp_bg_xjust = tmp_bg->bg.xjust;
1508    tmp_bg_yjust = tmp_bg->bg.yjust;
1509    tmp_bg_xperc = tmp_bg->bg.xperc;
1510    tmp_bg_yperc = tmp_bg->bg.yperc;
1511 }
1512
1513 static void
1514 BG_DialogSetFileName(DItem * di)
1515 {
1516    const char         *stmp;
1517    char                s[1024];
1518
1519    stmp = fullfileof(BackgroundGetBgFile(tmp_bg));
1520    Esnprintf(s, sizeof(s),
1521              _("Background definition information:\nName: %s\nFile: %s\n"),
1522              BackgroundGetName(tmp_bg), (stmp) ? stmp : _("-NONE-"));
1523    DialogItemSetText(di, s);
1524 }
1525
1526 static void
1527 BgDialogSetNewCurrent(Background * bg)
1528 {
1529    int                 i;
1530
1531    if (tmp_bg && tmp_bg != bg)
1532       BackgroundImagesKeep(tmp_bg, 0);
1533    tmp_bg = bg;
1534    BackgroundImagesKeep(tmp_bg, 1);
1535
1536    /* Fetch new BG values */
1537    BG_GetValues();
1538
1539    /* Update dialog items */
1540    BG_DialogSetFileName(bg_filename);
1541    DialogDrawItems(bg_sel_dialog, bg_filename, 0, 0, 99999, 99999);
1542
1543    DialogItemCheckButtonSetState(tmp_w[0], tmp_bg_image);
1544    DialogItemCheckButtonSetState(tmp_w[1], tmp_bg_keep_aspect);
1545    DialogItemCheckButtonSetState(tmp_w[2], tmp_bg_tile);
1546    DialogItemSliderSetVal(tmp_w[3], tmp_bg_r);
1547    DialogItemSliderSetVal(tmp_w[4], tmp_bg_g);
1548    DialogItemSliderSetVal(tmp_w[5], tmp_bg_b);
1549    DialogItemSliderSetVal(tmp_w[6], tmp_bg_xjust);
1550    DialogItemSliderSetVal(tmp_w[7], tmp_bg_yjust);
1551    DialogItemSliderSetVal(tmp_w[8], tmp_bg_yperc);
1552    DialogItemSliderSetVal(tmp_w[9], tmp_bg_xperc);
1553
1554    /* Redraw mini BG display */
1555    CB_DesktopMiniDisplayRedraw(NULL, 0, bg_mini_disp);
1556
1557    /* Redraw scrolling BG list */
1558    BG_RedrawView();
1559
1560    for (i = 0; i < 10; i++)
1561       DialogDrawItems(bg_sel_dialog, tmp_w[i], 0, 0, 99999, 99999);
1562 }
1563
1564 /* Duplicate current (tmp_bg) to new */
1565 static void
1566 CB_ConfigureNewBG(Dialog * d __UNUSED__, int val __UNUSED__,
1567                   void *data __UNUSED__)
1568 {
1569    char                s[1024];
1570    EColor              color;
1571    int                 lower, upper;
1572
1573    Esnprintf(s, sizeof(s), "__NEWBG_%i", (unsigned)time(NULL));
1574
1575    SET_COLOR(&color, tmp_bg_r, tmp_bg_g, tmp_bg_b);
1576
1577    tmp_bg = BackgroundCreate(s, &color,
1578                              tmp_bg->bg.file, tmp_bg_tile, tmp_bg_keep_aspect,
1579                              tmp_bg_xjust, tmp_bg_yjust,
1580                              tmp_bg_xperc, tmp_bg_yperc,
1581                              tmp_bg->top.file, tmp_bg->top.keep_aspect,
1582                              tmp_bg->top.xjust, tmp_bg->top.yjust,
1583                              tmp_bg->top.xperc, tmp_bg->top.yperc);
1584
1585    DialogItemSliderGetBounds(bg_sel_slider, &lower, &upper);
1586    upper += 4;
1587    DialogItemSliderSetBounds(bg_sel_slider, lower, upper);
1588
1589    DialogItemSliderSetVal(bg_sel_slider, 0);
1590    DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999);
1591
1592    DeskBackgroundSet(DesksGetCurrent(), tmp_bg);
1593
1594    BG_RedrawView();
1595
1596    autosave();
1597 }
1598
1599 static void
1600 CB_ConfigureDelBG(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
1601 {
1602    Background         *bg;
1603    int                 i, num;
1604    int                 slider, lower, upper;
1605
1606    num = ecore_list_count(bg_list);
1607    if (num <= 1)
1608       return;
1609
1610    bg = (Background *) ecore_list_goto(bg_list, tmp_bg);
1611    if (!bg)
1612       return;
1613
1614    i = ecore_list_index(bg_list);
1615    bg =
1616       (Background *) ecore_list_index_goto(bg_list,
1617                                            (i < num - 1) ? i + 1 : i - 1);
1618
1619    DeskBackgroundSet(DesksGetCurrent(), bg);
1620
1621    if (val == 0)
1622       BackgroundDestroy(tmp_bg);
1623    else
1624       BackgroundDelete(tmp_bg);
1625    tmp_bg = NULL;
1626
1627    DialogItemSliderGetBounds(bg_sel_slider, &lower, &upper);
1628    slider = DialogItemSliderGetVal(bg_sel_slider);
1629    upper -= 4;
1630    DialogItemSliderSetBounds(bg_sel_slider, lower, upper);
1631    if (slider > upper)
1632       DialogItemSliderSetVal(bg_sel_slider, upper);
1633
1634    BgDialogSetNewCurrent(bg);
1635
1636    autosave();
1637 }
1638
1639 /* Move current background to first position in list */
1640 static void
1641 CB_ConfigureFrontBG(Dialog * d __UNUSED__, int val __UNUSED__,
1642                     void *data __UNUSED__)
1643 {
1644    ecore_list_prepend(bg_list, ecore_list_node_remove(bg_list, tmp_bg));
1645    BGSettingsGoTo(tmp_bg);
1646    BG_RedrawView();
1647    autosave();
1648 }
1649
1650 /* Draw the scrolling background image window */
1651 static void
1652 BG_RedrawView(void)
1653 {
1654    Background         *bg;
1655    int                 x, w, h, num;
1656    Win                 win;
1657    Pixmap              pmap;
1658    ImageClass         *ic_button;
1659
1660    num = ecore_list_count(bg_list);
1661    if (num <= 0)
1662       return;
1663
1664    win = DialogItemAreaGetWindow(bg_sel);
1665    DialogItemAreaGetSize(bg_sel, &w, &h);
1666
1667    pmap = EGetWindowBackgroundPixmap(win);
1668
1669    ic_button = ImageclassFind("DIALOG_BUTTON", 1);
1670
1671    ImageclassApplySimple(ic_button, win, pmap, STATE_NORMAL, 0, 0, w, h);
1672
1673    x = -(num * (64 + 8) - w) * tmp_bg_sel_sliderval / (4 * num);
1674
1675    ECORE_LIST_FOR_EACH(bg_list, bg)
1676    {
1677       if (((x + 64 + 8) >= 0) && (x < w))
1678         {
1679            EImage             *im;
1680
1681            ImageclassApplySimple(ic_button, win, pmap,
1682                                  (bg == tmp_bg) ? STATE_CLICKED : STATE_NORMAL,
1683                                  x, 0, 64 + 8, 48 + 8);
1684
1685            if (BackgroundIsNone(bg))
1686              {
1687                 TextClass          *tc;
1688
1689                 tc = TextclassFind("DIALOG", 1);
1690                 if (tc)
1691                   {
1692                      int                 tw, th;
1693
1694                      TextSize(tc, 0, 0, STATE_NORMAL,
1695                               _("No\nBackground"), &tw, &th, 17);
1696                      TextDraw(tc, win, pmap, 0, 0, STATE_NORMAL,
1697                               _("No\nBackground"), x + 4,
1698                               4 + ((48 - th) / 2), 64, 48, 17, 512);
1699                   }
1700              }
1701            else
1702              {
1703                 im = BackgroundCacheMini(bg, 1, 0);
1704                 if (im)
1705                   {
1706                      EImageRenderOnDrawable(im, win, pmap, 0, x + 4, 4, 64, 48);
1707                      EImageFree(im);
1708                   }
1709              }
1710         }
1711       x += (64 + 8);
1712    }
1713
1714    EClearWindow(win);
1715 }
1716
1717 static void
1718 CB_BGAreaSlide(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__)
1719 {
1720    if (tmp_bg_sel_sliderval == tmp_bg_sel_sliderval_old)
1721       return;
1722    BG_RedrawView();
1723    tmp_bg_sel_sliderval_old = tmp_bg_sel_sliderval;
1724 }
1725
1726 static void
1727 CB_BGScan(Dialog * d, int val __UNUSED__, void *data __UNUSED__)
1728 {
1729    int                 num;
1730
1731    SoundPlay(SOUND_WAIT);
1732
1733    /* Forcing re-scan should not be necessary but provides the progress bars
1734     * so it actually looks like something is going on */
1735    Mode.backgrounds.force_scan = 1;
1736    ScanBackgroundMenu();
1737
1738    num = ecore_list_count(bg_list);
1739    DialogItemSliderSetBounds(bg_sel_slider, 0, num * 4);
1740    DialogDrawItems(d, bg_sel_slider, 0, 0, 99999, 99999);
1741    DialogItemCallCallback(d, bg_sel_slider);
1742 }
1743
1744 static void
1745 CB_BGAreaEvent(DItem * di __UNUSED__, int val __UNUSED__, void *data)
1746 {
1747    int                 x, num, w, h;
1748    Background         *bg;
1749    XEvent             *ev = (XEvent *) data;
1750
1751    DialogItemAreaGetSize(bg_sel, &w, &h);
1752
1753    switch (ev->type)
1754      {
1755      case ButtonPress:
1756         switch (ev->xbutton.button)
1757           {
1758           case 1:
1759              num = ecore_list_count(bg_list);
1760              x = (num * (64 + 8) - w) * tmp_bg_sel_sliderval / (4 * num) +
1761                 ev->xbutton.x;
1762              bg = (Background *) ecore_list_index_goto(bg_list, x / (64 + 8));
1763              if (!bg || bg == DeskBackgroundGet(DesksGetCurrent()))
1764                 break;
1765              BgDialogSetNewCurrent(bg);
1766              DeskBackgroundSet(DesksGetCurrent(), bg);
1767              autosave();
1768              break;
1769           case 4:
1770              tmp_bg_sel_sliderval += 4;
1771              goto do_slide;
1772           case 5:
1773              tmp_bg_sel_sliderval -= 4;
1774              goto do_slide;
1775            do_slide:
1776              DialogItemSliderSetVal(bg_sel_slider, tmp_bg_sel_sliderval);
1777              CB_BGAreaSlide(NULL, 0, NULL);
1778              DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999);
1779              break;
1780           }
1781      }
1782 }
1783
1784 static void
1785 CB_DesktopTimeout(Dialog * d __UNUSED__, int val __UNUSED__, void *data)
1786 {
1787    DItem              *di;
1788    char                s[256];
1789
1790    di = (DItem *) data;
1791    Esnprintf(s, sizeof(s), _("Unused backgrounds freed after %2i:%02i:%02i"),
1792              tmp_bg_timeout / 3600,
1793              (tmp_bg_timeout / 60) - (60 * (tmp_bg_timeout / 3600)),
1794              (tmp_bg_timeout) - (60 * (tmp_bg_timeout / 60)));
1795    DialogItemSetText(di, s);
1796    DialogDrawItems(bg_sel_dialog, di, 0, 0, 99999, 99999);
1797 }
1798
1799 static void
1800 BGSettingsGoTo(Background * bg)
1801 {
1802    int                 i, num;
1803
1804    if (!bg_sel_slider)
1805       return;
1806
1807    bg = (Background *) ecore_list_goto(bg_list, bg);
1808    if (!bg)
1809       return;
1810
1811    i = ecore_list_index(bg_list);
1812    num = ecore_list_count(bg_list);
1813    i = ((4 * num + 20) * i) / num - 8;
1814    if (i < 0)
1815       i = 0;
1816    else if (i > 4 * num)
1817       i = 4 * num;
1818    DialogItemSliderSetVal(bg_sel_slider, i);
1819    DialogDrawItems(bg_sel_dialog, bg_sel_slider, 0, 0, 99999, 99999);
1820    BgDialogSetNewCurrent(bg);
1821 }
1822
1823 static void
1824 CB_BGNext(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
1825 {
1826    Background         *bg;
1827
1828    bg = (Background *) ecore_list_goto(bg_list, tmp_bg);
1829    if (!bg)
1830       return;
1831
1832    bg =
1833       (Background *) ecore_list_index_goto(bg_list,
1834                                            ecore_list_index(bg_list) + val);
1835    if (!bg)
1836       return;
1837
1838    BGSettingsGoTo(bg);
1839    DeskBackgroundSet(DesksGetCurrent(), bg);
1840 }
1841
1842 static int
1843 BG_SortFileCompare(void *_bg1, void *_bg2)
1844 {
1845    Background         *bg1 = (Background *) _bg1;
1846    Background         *bg2 = (Background *) _bg2;
1847    const char         *name1, *name2;
1848
1849    /* return < 0 is b1 <  b2 */
1850    /* return > 0 is b1 >  b2 */
1851    /* return   0 is b1 == b2 */
1852
1853    name1 = BackgroundGetBgFile(bg1);
1854    name2 = BackgroundGetBgFile(bg2);
1855    if (name1 && name2)
1856       return strcmp(name1, name2);
1857    if (name1)
1858       return 1;
1859    if (name2)
1860       return -1;
1861    return (bg1 < bg2) ? -1 : 1;
1862 }
1863
1864 static void
1865 CB_BGSortFile(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__)
1866 {
1867    Background        **bglist;
1868    int                 i, num;
1869
1870    bglist = (Background **) ecore_list_items_get(bg_list, &num);
1871    if (!bglist)
1872       return;
1873
1874    /* remove them all from the list */
1875    for (i = 0; i < num; i++)
1876       ecore_list_node_remove(bg_list, bglist[i]);
1877    Quicksort((void **)bglist, 0, num - 2, BG_SortFileCompare);
1878    for (i = 0; i < num; i++)
1879       ecore_list_append(bg_list, bglist[i]);
1880    Efree(bglist);
1881
1882    BGSettingsGoTo(tmp_bg);
1883
1884    autosave();
1885 }
1886
1887 static void
1888 CB_BGSortAttrib(Dialog * d __UNUSED__, int val __UNUSED__,
1889                 void *data __UNUSED__)
1890 {
1891    Background        **bglist;
1892    int                 i, num;
1893
1894    bglist = (Background **) ecore_list_items_get(bg_list, &num);
1895    if (!bglist)
1896       return;
1897
1898    /* remove them all from the list */
1899    for (i = 0; i < num; i++)
1900       ecore_list_node_remove(bg_list, bglist[i]);
1901    for (i = 0; i < num; i++)
1902      {
1903         Background         *bg;
1904
1905         bg = bglist[i];
1906         if ((bg) && (bg->bg_tile) && (bg->bg.xperc == 0) && (bg->bg.yperc == 0))
1907           {
1908              ecore_list_prepend(bg_list, bg);
1909              bglist[i] = NULL;
1910           }
1911      }
1912    for (i = 0; i < num; i++)
1913      {
1914         Background         *bg;
1915
1916         bg = bglist[i];
1917         if (bg)
1918           {
1919              ecore_list_prepend(bg_list, bg);
1920              bglist[i] = NULL;
1921           }
1922      }
1923    Efree(bglist);
1924
1925    BGSettingsGoTo(tmp_bg);
1926
1927    autosave();
1928 }
1929
1930 #if 0                           /* Doesn't do anything useful */
1931 static void
1932 CB_BGSortContent(Dialog * d __UNUSED__, int val __UNUSED__,
1933                  void *data __UNUSED__)
1934 {
1935    Background        **bglist;
1936    int                 i, num;
1937
1938    bglist = (Background **) ecore_list_items_get(bg_list, &num);
1939    if (!bglist)
1940       return;
1941
1942    /* remove them all from the list */
1943    for (i = 0; i < num; i++)
1944       ecore_list_node_remove(bg_list, bglist[i]);
1945    for (i = 0; i < num; i++)
1946       ecore_list_prepend(bg_list, bglist[i]);
1947    Efree(bglist);
1948
1949    autosave();
1950 }
1951 #endif
1952
1953 #if 0                           /* Remove? */
1954 static void
1955 CB_DesktopMiniDisplayAreaInit(DItem * di, int val __UNUSED__,
1956                               void *data __UNUSED__)
1957 {
1958    CB_DesktopMiniDisplayRedraw(DialogItemGetDialog(di), 1, di);
1959 }
1960 #endif
1961
1962 static void
1963 CB_InitView(DItem * di __UNUSED__, int val __UNUSED__, void *data __UNUSED__)
1964 {
1965    tmp_bg_sel_sliderval_old = tmp_bg_sel_sliderval = -1;
1966    BGSettingsGoTo(tmp_bg);
1967 }
1968
1969 static void
1970 _DlgFillBackground(Dialog * d, DItem * table, void *data)
1971 {
1972    Background         *bg = (Background *) data;
1973    DItem              *di, *table2, *table3, *area, *label;
1974    int                 i, num;
1975    char                s[1024];
1976
1977    if (!Conf.backgrounds.no_scan)
1978       ScanBackgroundMenu();
1979
1980    if (!bg)
1981       bg = DeskBackgroundGet(DesksGetCurrent());
1982    if (!bg)
1983       bg = BackgroundFind("NONE");
1984    tmp_bg = bg;
1985
1986    BG_GetValues();
1987
1988    tmp_hiq = Conf.backgrounds.hiquality;
1989    tmp_userbg = Conf.backgrounds.user;
1990    tmp_root_hint = Conf.hints.set_xroot_info_on_root_window;
1991    tmp_bg_timeout = Conf.backgrounds.timeout;
1992
1993    bg_sel_dialog = d;
1994
1995    DialogItemTableSetOptions(table, 1, 0, 0, 0);
1996
1997    table2 = DialogAddItem(table, DITEM_TABLE);
1998    DialogItemTableSetOptions(table2, 2, 0, 1, 0);
1999
2000    di = bg_filename = DialogAddItem(table2, DITEM_TEXT);
2001    DialogItemSetFill(di, 1, 0);
2002    BG_DialogSetFileName(bg_filename);
2003
2004    table3 = DialogAddItem(table2, DITEM_TABLE);
2005
2006    di = tmp_w[0] = DialogAddItem(table3, DITEM_CHECKBUTTON);
2007    DialogItemSetText(di, _("Use background image"));
2008    DialogItemCheckButtonSetPtr(di, &tmp_bg_image);
2009
2010    di = tmp_w[1] = DialogAddItem(table3, DITEM_CHECKBUTTON);
2011    DialogItemSetText(di, _("Keep aspect on scale"));
2012    DialogItemCheckButtonSetPtr(di, &tmp_bg_keep_aspect);
2013
2014    di = tmp_w[2] = DialogAddItem(table3, DITEM_CHECKBUTTON);
2015    DialogItemSetText(di, _("Tile image across background"));
2016    DialogItemCheckButtonSetPtr(di, &tmp_bg_tile);
2017
2018    table2 = DialogAddItem(table, DITEM_TABLE);
2019    DialogItemTableSetOptions(table2, 4, 0, 1, 0);
2020    DialogItemSetFill(table2, 0, 0);
2021    DialogItemSetAlign(table2, 512, 0);
2022
2023    di = DialogAddItem(table2, DITEM_BUTTON);
2024    DialogItemSetText(di, _("Move to Front\n"));
2025    DialogItemSetCallback(di, CB_ConfigureFrontBG, 0, NULL);
2026    DialogBindKey(d, "F", CB_ConfigureFrontBG, 0, NULL);
2027
2028    di = DialogAddItem(table2, DITEM_BUTTON);
2029    DialogItemSetText(di, _("Duplicate\n"));
2030    DialogItemSetCallback(di, CB_ConfigureNewBG, 0, NULL);
2031
2032    di = DialogAddItem(table2, DITEM_BUTTON);
2033    DialogItemSetText(di, _("Unlist\n"));
2034    DialogItemSetCallback(di, CB_ConfigureDelBG, 0, NULL);
2035    DialogBindKey(d, "D", CB_ConfigureDelBG, 0, NULL);
2036
2037    di = DialogAddItem(table2, DITEM_BUTTON);
2038    DialogItemSetText(di, _("Delete File\n"));
2039    DialogItemSetCallback(di, CB_ConfigureDelBG, 1, NULL);
2040    DialogBindKey(d, "Delete", CB_ConfigureDelBG, 1, NULL);
2041
2042    table2 = DialogAddItem(table, DITEM_TABLE);
2043    DialogItemTableSetOptions(table2, 3, 0, 1, 0);
2044
2045    di = DialogAddItem(table2, DITEM_TEXT);
2046    DialogItemSetFill(di, 0, 0);
2047    DialogItemSetAlign(di, 512, 512);
2048    DialogItemSetText(di,
2049                      _("Background\n" "Image\n" "Scaling\n" "and\n"
2050                        "Alignment\n"));
2051
2052    table3 = DialogAddItem(table2, DITEM_TABLE);
2053    DialogItemTableSetOptions(table3, 3, 0, 0, 0);
2054
2055    di = DialogAddItem(table3, DITEM_NONE);
2056
2057    di = tmp_w[6] = DialogAddItem(table3, DITEM_SLIDER);
2058    DialogItemSliderSetMinLength(di, 10);
2059    DialogItemSliderSetBounds(di, 0, 1024);
2060    DialogItemSliderSetUnits(di, 1);
2061    DialogItemSliderSetJump(di, 64);
2062    DialogItemSliderSetValPtr(di, &tmp_bg_xjust);
2063
2064    di = DialogAddItem(table3, DITEM_NONE);
2065
2066    di = tmp_w[7] = DialogAddItem(table3, DITEM_SLIDER);
2067    DialogItemSliderSetMinLength(di, 10);
2068    DialogItemSliderSetOrientation(di, 0);
2069    DialogItemSetFill(di, 0, 1);
2070    DialogItemSliderSetBounds(di, 0, 1024);
2071    DialogItemSliderSetUnits(di, 1);
2072    DialogItemSliderSetJump(di, 64);
2073    DialogItemSliderSetValPtr(di, &tmp_bg_yjust);
2074
2075    di = bg_mini_disp = area = DialogAddItem(table3, DITEM_AREA);
2076    DialogItemAreaSetSize(di, 64, 48);
2077 #if 0                           /* Remove? */
2078    DialogItemAreaSetInitFunc(di, CB_DesktopMiniDisplayAreaInit);
2079 #endif
2080
2081    di = tmp_w[8] = DialogAddItem(table3, DITEM_SLIDER);
2082    DialogItemSliderSetMinLength(di, 10);
2083    DialogItemSliderSetOrientation(di, 0);
2084    DialogItemSetFill(di, 0, 1);
2085    DialogItemSliderSetBounds(di, 0, 1024);
2086    DialogItemSliderSetUnits(di, 1);
2087    DialogItemSliderSetJump(di, 64);
2088    DialogItemSliderSetValPtr(di, &tmp_bg_yperc);
2089
2090    di = DialogAddItem(table3, DITEM_NONE);
2091
2092    di = tmp_w[9] = DialogAddItem(table3, DITEM_SLIDER);
2093    DialogItemSliderSetMinLength(di, 10);
2094    DialogItemSliderSetBounds(di, 0, 1024);
2095    DialogItemSliderSetUnits(di, 1);
2096    DialogItemSliderSetJump(di, 64);
2097    DialogItemSliderSetValPtr(di, &tmp_bg_xperc);
2098
2099    table3 = DialogAddItem(table2, DITEM_TABLE);
2100    DialogItemTableSetOptions(table3, 2, 0, 0, 0);
2101
2102    di = DialogAddItem(table3, DITEM_TEXT);
2103    DialogItemSetColSpan(di, 2);
2104    DialogItemSetFill(di, 0, 0);
2105    DialogItemSetAlign(di, 512, 512);
2106    DialogItemSetText(di, _("BG Colour\n"));
2107
2108    di = DialogAddItem(table3, DITEM_TEXT);
2109    DialogItemSetFill(di, 0, 0);
2110    DialogItemSetAlign(di, 1024, 512);
2111    DialogItemSetText(di, _("Red:\n"));
2112
2113    di = tmp_w[3] = DialogAddItem(table3, DITEM_SLIDER);
2114    DialogItemSliderSetBounds(di, 0, 255);
2115    DialogItemSliderSetUnits(di, 1);
2116    DialogItemSliderSetJump(di, 16);
2117    DialogItemSliderSetValPtr(di, &tmp_bg_r);
2118
2119    di = DialogAddItem(table3, DITEM_TEXT);
2120    DialogItemSetFill(di, 0, 0);
2121    DialogItemSetAlign(di, 1024, 512);
2122    DialogItemSetText(di, _("Green:\n"));
2123
2124    di = tmp_w[4] = DialogAddItem(table3, DITEM_SLIDER);
2125    DialogItemSliderSetBounds(di, 0, 255);
2126    DialogItemSliderSetUnits(di, 1);
2127    DialogItemSliderSetJump(di, 16);
2128    DialogItemSliderSetValPtr(di, &tmp_bg_g);
2129
2130    di = DialogAddItem(table3, DITEM_TEXT);
2131    DialogItemSetFill(di, 0, 0);
2132    DialogItemSetAlign(di, 1024, 512);
2133    DialogItemSetText(di, _("Blue:\n"));
2134
2135    di = tmp_w[5] = DialogAddItem(table3, DITEM_SLIDER);
2136    DialogItemSliderSetBounds(di, 0, 255);
2137    DialogItemSliderSetUnits(di, 1);
2138    DialogItemSliderSetJump(di, 16);
2139    DialogItemSliderSetValPtr(di, &tmp_bg_b);
2140
2141    for (i = 0; i < 10; i++)
2142       DialogItemSetCallback(tmp_w[i], CB_DesktopMiniDisplayRedraw, 0, area);
2143
2144    di = DialogAddItem(table, DITEM_SEPARATOR);
2145
2146    table2 = DialogAddItem(table, DITEM_TABLE);
2147    DialogItemTableSetOptions(table2, 3, 0, 0, 0);
2148
2149    table3 = DialogAddItem(table2, DITEM_TABLE);
2150    DialogItemTableSetOptions(table3, 2, 0, 0, 0);
2151
2152    di = DialogAddItem(table3, DITEM_BUTTON);
2153    DialogItemSetFill(di, 0, 0);
2154    DialogItemSetText(di, "<-");
2155    DialogItemSetCallback(di, CB_BGNext, -1, NULL);
2156    DialogBindKey(d, "Left", CB_BGNext, -1, NULL);
2157
2158    di = DialogAddItem(table3, DITEM_BUTTON);
2159    DialogItemSetFill(di, 0, 0);
2160    DialogItemSetText(di, "->");
2161    DialogItemSetCallback(di, CB_BGNext, 1, NULL);
2162    DialogBindKey(d, "Right", CB_BGNext, 1, NULL);
2163
2164    di = DialogAddItem(table2, DITEM_BUTTON);
2165    DialogItemSetFill(di, 0, 0);
2166    DialogItemSetText(di, _("Pre-scan BG's"));
2167    DialogItemSetCallback(di, CB_BGScan, 0, NULL);
2168
2169    table3 = DialogAddItem(table2, DITEM_TABLE);
2170    DialogItemTableSetOptions(table3, 3, 0, 0, 0);
2171
2172    di = DialogAddItem(table3, DITEM_BUTTON);
2173    DialogItemSetFill(di, 0, 0);
2174    DialogItemSetText(di, _("Sort by File"));
2175    DialogItemSetCallback(di, CB_BGSortFile, 0, NULL);
2176
2177    di = DialogAddItem(table3, DITEM_BUTTON);
2178    DialogItemSetFill(di, 0, 0);
2179    DialogItemSetText(di, _("Sort by Attr."));
2180    DialogItemSetCallback(di, CB_BGSortAttrib, 0, NULL);
2181
2182 #if 0                           /* Doesn't do anything useful */
2183    di = DialogAddItem(table3, DITEM_BUTTON);
2184    DialogItemSetFill(di, 0, 0);
2185    DialogItemSetText(di, _("Sort by Image"));
2186    DialogItemSetCallback(di, CB_BGSortContent, 0, NULL);
2187 #endif
2188
2189    di = bg_sel = DialogAddItem(table, DITEM_AREA);
2190    DialogItemAreaSetSize(di, 160, 56);
2191    DialogItemAreaSetEventFunc(di, CB_BGAreaEvent);
2192    DialogItemAreaSetInitFunc(di, CB_InitView);
2193
2194    num = ecore_list_count(bg_list);
2195    di = bg_sel_slider = DialogAddItem(table, DITEM_SLIDER);
2196    DialogItemSliderSetBounds(di, 0, num * 4);
2197    DialogItemSliderSetUnits(di, 1);
2198    DialogItemSliderSetJump(di, 9);
2199    DialogItemSliderSetValPtr(di, &tmp_bg_sel_sliderval);
2200    DialogItemSetCallback(bg_sel_slider, CB_BGAreaSlide, 0, NULL);
2201
2202    di = DialogAddItem(table, DITEM_SEPARATOR);
2203
2204    di = DialogAddItem(table, DITEM_CHECKBUTTON);
2205    DialogItemSetText(di, _("Use dithering in Hi-Colour"));
2206    DialogItemCheckButtonSetPtr(di, &tmp_hiq);
2207
2208    di = DialogAddItem(table, DITEM_CHECKBUTTON);
2209    DialogItemSetText(di, _("Background overrides theme"));
2210    DialogItemCheckButtonSetPtr(di, &tmp_userbg);
2211
2212    di = DialogAddItem(table, DITEM_CHECKBUTTON);
2213    DialogItemSetText(di,
2214                      _("Enable background transparency compatibility mode"));
2215    DialogItemCheckButtonSetPtr(di, &tmp_root_hint);
2216
2217    di = DialogAddItem(table, DITEM_SEPARATOR);
2218
2219    di = label = DialogAddItem(table, DITEM_TEXT);
2220    DialogItemSetAlign(di, 512, 512);
2221    Esnprintf(s, sizeof(s), _("Unused backgrounds freed after %2i:%02i:%02i"),
2222              tmp_bg_timeout / 3600,
2223              (tmp_bg_timeout / 60) - (60 * (tmp_bg_timeout / 3600)),
2224              (tmp_bg_timeout) - (60 * (tmp_bg_timeout / 60)));
2225    DialogItemSetText(di, s);
2226
2227    di = DialogAddItem(table, DITEM_SLIDER);
2228    DialogItemSliderSetMinLength(di, 10);
2229    DialogItemSliderSetBounds(di, 0, 60 * 60 * 4);
2230    DialogItemSliderSetUnits(di, 30);
2231    DialogItemSliderSetJump(di, 60);
2232    DialogItemSliderSetValPtr(di, &tmp_bg_timeout);
2233    DialogItemSetCallback(di, CB_DesktopTimeout, 0, label);
2234 }
2235
2236 const DialogDef     DlgBackground = {
2237    "CONFIGURE_BG",
2238    N_("Background"),
2239    N_("Desktop Background Settings"),
2240    SOUND_SETTINGS_BG,
2241    "pix/bg.png",
2242    N_("Enlightenment Desktop\n" "Background Settings Dialog\n"),
2243    _DlgFillBackground,
2244    DLG_OAC, CB_ConfigureBG,
2245 };
2246
2247 #endif /* ENABLE_DIALOGS */
2248
2249 /*
2250  * IPC functions
2251  */
2252
2253 static void
2254 BackgroundSet1(const char *name, const char *params)
2255 {
2256    const char         *p = params;
2257    char                type[FILEPATH_LEN_MAX];
2258    int                 len, value;
2259    Background         *bg;
2260    EColor              color;
2261
2262    if (!p || !p[0])
2263       return;
2264
2265    bg = BackgroundFind(name);
2266    if (!bg)
2267      {
2268         SET_COLOR(&color, 0, 0, 0);
2269         bg = BackgroundCreate(name, &color, NULL, 0, 0, 0,
2270                               0, 0, 0, NULL, 0, 0, 0, 0, 0);
2271         if (!bg)
2272           {
2273              IpcPrintf("Error: could not create background '%s'.", name);
2274              return;
2275           }
2276      }
2277
2278    type[0] = '\0';
2279    len = 0;
2280    sscanf(p, "%400s %n", type, &len);
2281    p += len;
2282    value = atoi(p);
2283
2284    if (!strcmp(type, "bg.solid"))
2285      {
2286         int                 r, b, g;
2287
2288         r = g = b = 0;
2289         sscanf(p, "%i %i %i", &r, &g, &b);
2290         SET_COLOR(&(bg->bg_solid), r, g, b);
2291      }
2292    else if (!strcmp(type, "bg.file"))
2293      {
2294         Efree(bg->bg.file);
2295         bg->bg.file = Estrdup(p);
2296      }
2297    else if (!strcmp(type, "bg.tile"))
2298      {
2299         bg->bg_tile = value;
2300      }
2301    else if (!strcmp(type, "bg.keep_aspect"))
2302      {
2303         bg->bg.keep_aspect = value;
2304      }
2305    else if (!strcmp(type, "bg.xjust"))
2306      {
2307         bg->bg.xjust = value;
2308      }
2309    else if (!strcmp(type, "bg.yjust"))
2310      {
2311         bg->bg.yjust = value;
2312      }
2313    else if (!strcmp(type, "bg.xperc"))
2314      {
2315         bg->bg.xperc = value;
2316      }
2317    else if (!strcmp(type, "bg.yperc"))
2318      {
2319         bg->bg.yperc = value;
2320      }
2321    else if (!strcmp(type, "top.file"))
2322      {
2323         Efree(bg->top.file);
2324         bg->top.file = Estrdup(p);
2325      }
2326    else if (!strcmp(type, "top.keep_aspect"))
2327      {
2328         bg->top.keep_aspect = value;
2329      }
2330    else if (!strcmp(type, "top.xjust"))
2331      {
2332         bg->top.xjust = value;
2333      }
2334    else if (!strcmp(type, "top.yjust"))
2335      {
2336         bg->top.yjust = value;
2337      }
2338    else if (!strcmp(type, "top.xperc"))
2339      {
2340         bg->top.xperc = value;
2341      }
2342    else if (!strcmp(type, "top.yperc"))
2343      {
2344         bg->top.yperc = value;
2345      }
2346    else
2347      {
2348         IpcPrintf("Error: unknown background value type '%s'.", type);
2349      }
2350    autosave();
2351 }
2352
2353 static void
2354 BackgroundSet2(const char *name, const char *params)
2355 {
2356    Background         *bg;
2357    EColor              color;
2358    unsigned int        i;
2359    int                 r, g, b;
2360    char                bgf[FILEPATH_LEN_MAX], topf[FILEPATH_LEN_MAX];
2361    int                 tile, keep_aspect, tkeep_aspect;
2362    int                 xjust, yjust, xperc, yperc;
2363    int                 txjust, tyjust, txperc, typerc;
2364
2365    if (params == NULL)
2366       return;
2367
2368    bgf[0] = topf[0] = '\0';
2369    r = g = b = 99;
2370    i = sscanf(params,
2371               "%i %i %i %4000s %i %i %i %i %i %i %4000s %i %i %i %i %i",
2372               &r, &g, &b,
2373               bgf, &tile, &keep_aspect, &xjust, &yjust, &xperc, &yperc,
2374               topf, &tkeep_aspect, &txjust, &tyjust, &txperc, &typerc);
2375    SET_COLOR(&color, r, g, b);
2376
2377    bg = BackgroundFind(name);
2378    if (bg)
2379      {
2380         BackgroundModify(bg, &color, bgf, tile, keep_aspect, xjust,
2381                          yjust, xperc, yperc, topf, tkeep_aspect,
2382                          txjust, tyjust, txperc, typerc);
2383      }
2384    else
2385      {
2386         bg = BackgroundCreate(name, &color, bgf, tile, keep_aspect, xjust,
2387                               yjust, xperc, yperc, topf, tkeep_aspect,
2388                               txjust, tyjust, txperc, typerc);
2389      }
2390 }
2391
2392 static void
2393 BackgroundsIpc(const char *params)
2394 {
2395    const char         *p;
2396    char                cmd[128], prm[128], buf[4096];
2397    int                 i, len, num, len2;
2398    Background         *bg;
2399
2400    len = len2 = 0;
2401    cmd[0] = prm[0] = '\0';
2402    p = params;
2403    if (p)
2404      {
2405         sscanf(p, "%100s %n%100s %n", cmd, &len2, prm, &len);
2406         p += len;
2407      }
2408
2409    if (!p || cmd[0] == '?')
2410      {
2411         for (i = 0; i < (int)DesksGetNumber(); i++)
2412           {
2413              bg = DeskBackgroundGet(DeskGet(i));
2414              if (bg)
2415                 IpcPrintf("%i %s\n", i, BackgroundGetName(bg));
2416              else
2417                 IpcPrintf("%i %s\n", i, "-NONE-");
2418           }
2419      }
2420    else if (!strncmp(cmd, "apply", 2))
2421      {
2422         Window              xwin;
2423         Win                 win;
2424
2425         bg = BackgroundFind(prm);
2426         if (!bg)
2427            return;
2428
2429         xwin = None;
2430         sscanf(p, "%lx", &xwin);
2431
2432         win = ECreateWinFromXwin(xwin);
2433         if (!win)
2434            return;
2435         BackgroundApplyWin(bg, win);
2436         EDestroyWin(win);
2437      }
2438    else if (!strncmp(cmd, "del", 2))
2439      {
2440         BackgroundDestroyByName(prm);
2441      }
2442    else if (!strncmp(cmd, "list", 2))
2443      {
2444         ECORE_LIST_FOR_EACH(bg_list, bg) IpcPrintf("%s\n", bg->name);
2445      }
2446    else if (!strncmp(cmd, "load", 2))
2447      {
2448         bg = BackgroundFind(prm);
2449         if (bg)
2450           {
2451              IpcPrintf("Background already defined\n");
2452           }
2453         else
2454           {
2455              bg = BrackgroundCreateFromImage(prm, p, NULL, 0);
2456           }
2457      }
2458    else if (!strncmp(cmd, "set", 2))
2459      {
2460         BackgroundSet1(prm, p);
2461      }
2462    else if (!strncmp(cmd, "show", 2))
2463      {
2464         bg = BackgroundFind(prm);
2465
2466         if (bg)
2467           {
2468              BackgroundGetInfoString1(bg, buf, sizeof(buf));
2469              IpcPrintf("%s\n", buf);
2470           }
2471         else
2472            IpcPrintf("Error: background '%s' does not exist.", prm);
2473      }
2474    else if (!strcmp(cmd, "use"))
2475      {
2476         if (!strcmp(prm, "-"))
2477            bg = NULL;
2478         else
2479            bg = BackgroundFind(prm);
2480
2481         num = DesksGetCurrentNum();
2482         sscanf(p, "%d %n", &num, &len);
2483         DeskBackgroundSet(DeskGet(num), bg);
2484         autosave();
2485      }
2486    else if (!strncmp(cmd, "xget", 2))
2487      {
2488         bg = BackgroundFind(prm);
2489
2490         if (bg)
2491           {
2492              BackgroundGetInfoString2(bg, buf, sizeof(buf));
2493              IpcPrintf("%s\n", buf);
2494           }
2495         else
2496            IpcPrintf("Error: background '%s' does not exist.", prm);
2497      }
2498    else if (!strncmp(cmd, "xset", 2))
2499      {
2500         BackgroundSet2(prm, p);
2501      }
2502    else
2503      {
2504         /* Compatibility with pre- 0.16.8 clients */
2505         BackgroundSet1(cmd, params + len2);
2506      }
2507 }
2508
2509 static void
2510 IPC_BackgroundUse(const char *params)
2511 {
2512    char                name[1024];
2513    const char         *p;
2514    Background         *bg;
2515    int                 i, l;
2516
2517    p = params;
2518    name[0] = '\0';
2519    l = 0;
2520    sscanf(p, "%1000s %n", name, &l);
2521    p += l;
2522
2523    bg = BackgroundFind(name);
2524    if (!bg)
2525       return;
2526
2527    for (;;)
2528      {
2529         i = l = -1;
2530         sscanf(p, "%d %n", &i, &l);
2531         p += l;
2532         if (i < 0)
2533            break;
2534         DeskBackgroundSet(DeskGet(i), bg);
2535      }
2536
2537    autosave();
2538 }
2539
2540 static const IpcItem BackgroundsIpcArray[] = {
2541    {
2542     BackgroundsIpc,
2543     "background", "bg",
2544     "Background commands",
2545     "  background                       Show current background\n"
2546     "  background apply <name> <win>    Apply background to window\n"
2547     "  background del <name>            Delete background\n"
2548     "  background list                  Show all background\n"
2549     "  background load <name> <file>    Load new wallpaper from file\n"
2550     "  background set <name> ...        Set background parameters\n"
2551     "  background show <name>           Show background info\n"
2552     "  background use <name> <desks...> Switch to background <name>\n"
2553     "  background xget <name>           Special show background parameters\n"
2554     "  background xset <name> ...       Special set background parameters\n"}
2555    ,
2556    {
2557     IPC_BackgroundUse, "use_bg", NULL, "Deprecated - do not use", NULL}
2558    ,
2559 };
2560 #define N_IPC_FUNCS (sizeof(BackgroundsIpcArray)/sizeof(IpcItem))
2561
2562 /*
2563  * Configuration items
2564  */
2565 static const CfgItem BackgroundsCfgItems[] = {
2566    CFG_ITEM_BOOL(Conf.backgrounds, hiquality, 1),
2567    CFG_ITEM_BOOL(Conf.backgrounds, user, 1),
2568    CFG_ITEM_BOOL(Conf.backgrounds, no_scan, 0),
2569    CFG_ITEM_INT(Conf.backgrounds, timeout, 240),
2570 };
2571 #define N_CFG_ITEMS (sizeof(BackgroundsCfgItems)/sizeof(CfgItem))
2572
2573 /*
2574  * Module descriptor
2575  */
2576 extern const EModule ModBackgrounds;
2577 const EModule       ModBackgrounds = {
2578    "backgrounds", "bg",
2579    BackgroundsSighan,
2580    {N_IPC_FUNCS, BackgroundsIpcArray},
2581    {N_CFG_ITEMS, BackgroundsCfgItems}
2582 };