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