1/*
2 * Builtin bitmap image generation/lookup.
3 */
4
5#include "ctwm.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9
10#include <X11/Xmu/Drawing.h>
11
12#include "screen.h"
13#include "drawing.h"
14#include "icons_builtin.h"
15
16#include "image.h"
17#include "image_bitmap_builtin.h"
18
19
20/*
21 * Firstly, the plain built-in titlebar symbols.  These are the ones
22 * specified with names like ":resize".  For various reasons, these
23 * currently return Pixmap's, unlike most of our other builtins that
24 * generate Image's.  Possible cleanup candidate.
25 */
26#define DEF_BI_PPM(nm) Pixmap nm(unsigned int *widthp, unsigned int *heightp)
27static DEF_BI_PPM(CreateXLogoPixmap);
28static DEF_BI_PPM(CreateResizePixmap);
29static DEF_BI_PPM(CreateQuestionPixmap);
30static DEF_BI_PPM(CreateMenuPixmap);
31static DEF_BI_PPM(CreateDotPixmap);
32
33
34
35/*
36 * Look up and return a ":something" (not a ":xpm:something").
37 *
38 * Names of the form :name refer to hardcoded images that are scaled to
39 * look nice in title buttons.  Eventually, it would be nice to put in a
40 * menu symbol as well....
41 */
42Pixmap
43get_builtin_plain_pixmap(const char *name, unsigned int *widthp,
44                         unsigned int *heightp)
45{
46	int i;
47	static struct {
48		char *name;
49		DEF_BI_PPM((*proc));
50	} pmtab[] = {
51		/* Lookup table for our various default pixmaps */
52		{ TBPM_DOT,         CreateDotPixmap },
53		{ TBPM_ICONIFY,     CreateDotPixmap },
54		{ TBPM_RESIZE,      CreateResizePixmap },
55		{ TBPM_XLOGO,       CreateXLogoPixmap },
56		{ TBPM_DELETE,      CreateXLogoPixmap },
57		{ TBPM_MENU,        CreateMenuPixmap },
58		{ TBPM_QUESTION,    CreateQuestionPixmap },
59	};
60
61	/* Seatbelts */
62	if(!name || name[0] != ':') {
63		return None;
64	}
65	if(!widthp || !heightp) {
66		return None;
67	}
68
69
70	/* Find it */
71	for(i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
72		if(strcasecmp(pmtab[i].name, name) == 0) {
73			Pixmap pm = (*pmtab[i].proc)(widthp, heightp);
74			if(pm == None) {
75				fprintf(stderr, "%s:  unable to build bitmap \"%s\"\n",
76				        ProgramName, name);
77				return None;
78			}
79			return pm;
80		}
81	}
82
83	/* Didn't find it */
84	fprintf(stderr, "%s:  no such built-in bitmap \"%s\"\n",
85	        ProgramName, name);
86	return None;
87}
88
89
90/*
91 * Individual generators for those plain pixmaps
92 */
93DEF_BI_PPM(CreateXLogoPixmap)
94{
95	int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
96	if(h < 0) {
97		h = 0;
98	}
99
100	*widthp = *heightp = (unsigned int) h;
101	if(Scr->tbpm.xlogo == None) {
102		GC gc, gcBack;
103
104		Scr->tbpm.xlogo = XCreatePixmap(dpy, Scr->Root, h, h, 1);
105		gc = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL);
106		XSetForeground(dpy, gc, 0);
107		XFillRectangle(dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
108		XSetForeground(dpy, gc, 1);
109		gcBack = XCreateGC(dpy, Scr->tbpm.xlogo, 0L, NULL);
110		XSetForeground(dpy, gcBack, 0);
111
112		/*
113		 * draw the logo large so that it gets as dense as possible; then white
114		 * out the edges so that they look crisp
115		 */
116		XmuDrawLogo(dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
117		XDrawRectangle(dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
118
119		/*
120		 * done drawing
121		 */
122		XFreeGC(dpy, gc);
123		XFreeGC(dpy, gcBack);
124	}
125	return Scr->tbpm.xlogo;
126}
127
128
129DEF_BI_PPM(CreateResizePixmap)
130{
131	int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
132	if(h < 1) {
133		h = 1;
134	}
135
136	*widthp = *heightp = (unsigned int) h;
137	if(Scr->tbpm.resize == None) {
138		XPoint  points[3];
139		GC gc;
140		int w;
141		int lw;
142
143		/*
144		 * create the pixmap
145		 */
146		Scr->tbpm.resize = XCreatePixmap(dpy, Scr->Root, h, h, 1);
147		gc = XCreateGC(dpy, Scr->tbpm.resize, 0L, NULL);
148		XSetForeground(dpy, gc, 0);
149		XFillRectangle(dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
150		XSetForeground(dpy, gc, 1);
151		lw = h / 16;
152		if(lw == 1) {
153			lw = 0;
154		}
155		XSetLineAttributes(dpy, gc, lw, LineSolid, CapButt, JoinMiter);
156
157		/*
158		 * draw the resize button,
159		 */
160		w = (h * 2) / 3;
161		points[0].x = w;
162		points[0].y = 0;
163		points[1].x = w;
164		points[1].y = w;
165		points[2].x = 0;
166		points[2].y = w;
167		XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
168		w = w / 2;
169		points[0].x = w;
170		points[0].y = 0;
171		points[1].x = w;
172		points[1].y = w;
173		points[2].x = 0;
174		points[2].y = w;
175		XDrawLines(dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
176
177		/*
178		 * done drawing
179		 */
180		XFreeGC(dpy, gc);
181	}
182	return Scr->tbpm.resize;
183}
184
185
186#define questionmark_width 8
187#define questionmark_height 8
188static char questionmark_bits[] = {
189	0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18
190};
191
192DEF_BI_PPM(CreateQuestionPixmap)
193{
194	*widthp = questionmark_width;
195	*heightp = questionmark_height;
196	if(Scr->tbpm.question == None) {
197		Scr->tbpm.question = XCreateBitmapFromData(dpy, Scr->Root,
198		                     questionmark_bits,
199		                     questionmark_width,
200		                     questionmark_height);
201	}
202	/*
203	 * this must succeed or else we are in deep trouble elsewhere
204	 */
205	return Scr->tbpm.question;
206}
207#undef questionmark_height
208#undef questionmark_width
209
210
211DEF_BI_PPM(CreateMenuPixmap)
212{
213	return (CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2, widthp,
214	                       heightp));
215}
216
217DEF_BI_PPM(CreateDotPixmap)
218{
219	int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
220
221	h = h * 3 / 4;
222	if(h < 1) {
223		h = 1;
224	}
225	if(!(h & 1)) {
226		h--;
227	}
228	*widthp = *heightp = (unsigned int) h;
229	if(Scr->tbpm.delete == None) {
230		GC  gc;
231		Pixmap pix;
232
233		pix = Scr->tbpm.delete = XCreatePixmap(dpy, Scr->Root, h, h, 1);
234		gc = XCreateGC(dpy, pix, 0L, NULL);
235		XSetLineAttributes(dpy, gc, h, LineSolid, CapRound, JoinRound);
236		XSetForeground(dpy, gc, 0L);
237		XFillRectangle(dpy, pix, gc, 0, 0, h, h);
238		XSetForeground(dpy, gc, 1L);
239		XDrawLine(dpy, pix, gc, h / 2, h / 2, h / 2, h / 2);
240		XFreeGC(dpy, gc);
241	}
242	return Scr->tbpm.delete;
243}
244
245#undef DEF_BI_PPM
246
247
248
249/*
250 * Next, the "3D/scalable" builtins.  These are the ones specified with
251 * names like ":xpm:resize".  I'm not entirely clear on how these differ
252 * from ":resize"; they both vary by UseThreeDTitles and look the same.
253 * But, whatever.
254 *
255 * These yield [ctwm struct] Image's rather than [X11 type] Pixmap's.
256 */
257#define DEF_BI_SPM(nm) Image *nm(ColorPair cp)
258static DEF_BI_SPM(Create3DMenuImage);
259static DEF_BI_SPM(Create3DDotImage);
260static DEF_BI_SPM(Create3DResizeImage);
261static DEF_BI_SPM(Create3DZoomImage);
262static DEF_BI_SPM(Create3DBarImage);
263static DEF_BI_SPM(Create3DVertBarImage);
264static DEF_BI_SPM(Create3DCrossImage);
265static DEF_BI_SPM(Create3DIconifyImage);
266static DEF_BI_SPM(Create3DSunkenResizeImage);
267static DEF_BI_SPM(Create3DBoxImage);
268
269
270/*
271 * Main lookup
272 *
273 * This is where we find ":xpm:something".  Note that these are _not_
274 * XPM's, and have no relation to the configurable XPM support, which we
275 * get with images specified as "xpm:something" (no leading colon).
276 * That's not confusing at all.
277 */
278Image *
279get_builtin_scalable_pixmap(const char *name, ColorPair cp)
280{
281	int    i;
282	static struct {
283		char *name;
284		DEF_BI_SPM((*proc));
285	} pmtab[] = {
286		/* Lookup for ":xpm:" pixmaps */
287		{ TBPM_3DDOT,       Create3DDotImage },
288		{ TBPM_3DRESIZE,    Create3DResizeImage },
289		{ TBPM_3DMENU,      Create3DMenuImage },
290		{ TBPM_3DZOOM,      Create3DZoomImage },
291		{ TBPM_3DBAR,       Create3DBarImage },
292		{ TBPM_3DVBAR,      Create3DVertBarImage },
293		{ TBPM_3DCROSS,     Create3DCrossImage },
294		{ TBPM_3DICONIFY,   Create3DIconifyImage },
295		{ TBPM_3DBOX,       Create3DBoxImage },
296		{ TBPM_3DSUNKEN_RESIZE, Create3DSunkenResizeImage },
297	};
298
299	/* Seatbelts */
300	if(!name || (strncmp(name, ":xpm:", 5) != 0)) {
301		return NULL;
302	}
303
304	for(i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
305		if(strcasecmp(pmtab[i].name, name) == 0) {
306			Image *image = (*pmtab[i].proc)(cp);
307			if(image == NULL) {
308				fprintf(stderr, "%s:  unable to build pixmap \"%s\"\n",
309				        ProgramName, name);
310				return NULL;
311			}
312			return image;
313		}
314	}
315
316	fprintf(stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
317	return NULL;
318}
319
320
321
322#define LEVITTE_TEST
323static DEF_BI_SPM(Create3DCrossImage)
324{
325	Image *image;
326	int        h;
327	int    point;
328	int midpoint;
329
330	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
331	if(!(h & 1)) {
332		h--;
333	}
334	point = 4;
335	midpoint = h / 2;
336
337	image = AllocImage();
338	if(! image) {
339		return (None);
340	}
341	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
342	if(image->pixmap == None) {
343		free(image);
344		return (None);
345	}
346
347	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
348	             off, true, false);
349
350#ifdef LEVITTE_TEST
351	FB(cp.shadc, cp.shadd);
352	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 1, point - 1, point - 1,
353	          point + 1);
354	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 1, point, point,
355	          point + 1);
356	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point - 1, point + 1, midpoint - 2,
357	          midpoint);
358	XDrawLine(dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint + 2,
359	          h - point - 3, h - point - 1);
360	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, point + 1, h - point - 3,
361	          h - point - 2);
362	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point - 1, h - point - 2,
363	          midpoint - 2, midpoint);
364	XDrawLine(dpy, image->pixmap, Scr->NormalGC, midpoint, midpoint - 2,
365	          h - point - 2, point - 1);
366	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, h - point - 2,
367	          h - point - 2, point);
368#endif
369
370	FB(cp.shadd, cp.shadc);
371#ifdef LEVITTE_TEST
372	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 2, point + 1,
373	          h - point - 1, h - point - 2);
374	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 2, point, midpoint,
375	          midpoint - 2);
376	XDrawLine(dpy, image->pixmap, Scr->NormalGC, midpoint + 2, midpoint, h - point,
377	          h - point - 2);
378	XDrawLine(dpy, image->pixmap, Scr->NormalGC, h - point, h - point - 2,
379	          h - point - 2, h - point);
380	XDrawLine(dpy, image->pixmap, Scr->NormalGC, h - point - 1, h - point - 2,
381	          h - point - 2, h - point - 1);
382#else
383	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, point, h - point - 1,
384	          h - point - 1);
385	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point - 1, point, h - point - 1,
386	          h - point);
387	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, point - 1, h - point,
388	          h - point - 1);
389#endif
390
391#ifdef LEVITTE_TEST
392	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, h - point - 1, point,
393	          h - point - 1);
394	XDrawLine(dpy, image->pixmap, Scr->NormalGC, h - point - 1, point,
395	          h - point - 1, point);
396#else
397	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, h - point - 1,
398	          h - point - 1, point);
399#endif
400#ifdef LEVITTE_TEST
401	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 1, h - point - 1,
402	          h - point - 1, point + 1);
403	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point + 1, h - point, midpoint,
404	          midpoint + 2);
405	XDrawLine(dpy, image->pixmap, Scr->NormalGC, midpoint + 2, midpoint, h - point,
406	          point + 1);
407#else
408	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point - 1, h - point - 1,
409	          h - point - 1, point - 1);
410	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, h - point, h - point,
411	          point);
412#endif
413
414	image->width  = h;
415	image->height = h;
416
417	return (image);
418}
419#undef LEVITTE_TEST
420
421static DEF_BI_SPM(Create3DIconifyImage)
422{
423	Image *image;
424	int     h;
425	int point;
426
427	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
428	if(!(h & 1)) {
429		h--;
430	}
431	point = ((h / 2 - 2) * 2 + 1) / 3;
432
433	image = AllocImage();
434	if(! image) {
435		return (None);
436	}
437	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
438	if(image->pixmap == None) {
439		free(image);
440		return (None);
441	}
442
443	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
444	             off, true, false);
445	FB(cp.shadd, cp.shadc);
446	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, point, h / 2, h - point);
447	XDrawLine(dpy, image->pixmap, Scr->NormalGC, point, point, h - point, point);
448
449	FB(cp.shadc, cp.shadd);
450	XDrawLine(dpy, image->pixmap, Scr->NormalGC, h - point, point, h / 2 + 1,
451	          h - point);
452	XDrawLine(dpy, image->pixmap, Scr->NormalGC, h - point - 1, point + 1,
453	          h / 2 + 1, h - point - 1);
454
455	image->width  = h;
456	image->height = h;
457
458	return (image);
459}
460
461static DEF_BI_SPM(Create3DSunkenResizeImage)
462{
463	int     h;
464	Image *image;
465
466	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
467	if(!(h & 1)) {
468		h--;
469	}
470
471	image = AllocImage();
472	if(! image) {
473		return (None);
474	}
475	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
476	if(image->pixmap == None) {
477		free(image);
478		return (None);
479	}
480
481	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
482	             off, true, false);
483	Draw3DBorder(image->pixmap, 3, 3, h - 6, h - 6, 1, cp, on, true, false);
484	Draw3DBorder(image->pixmap, 3, ((h - 6) / 3) + 3, ((h - 6) * 2 / 3) + 1,
485	             ((h - 6) * 2 / 3) + 1, 1, cp, on, true, false);
486	Draw3DBorder(image->pixmap, 3, ((h - 6) * 2 / 3) + 3, ((h - 6) / 3) + 1,
487	             ((h - 6) / 3) + 1, 1, cp, on, true, false);
488
489	image->width  = h;
490	image->height = h;
491
492	return (image);
493}
494
495static DEF_BI_SPM(Create3DBoxImage)
496{
497	int     h;
498	Image   *image;
499
500	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
501	if(!(h & 1)) {
502		h--;
503	}
504
505	image = AllocImage();
506	if(! image) {
507		return (None);
508	}
509	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
510	if(image->pixmap == None) {
511		free(image);
512		return (None);
513	}
514
515	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
516	             off, true, false);
517	Draw3DBorder(image->pixmap, (h / 2) - 4, (h / 2) - 4, 9, 9, 1, cp,
518	             off, true, false);
519
520	image->width  = h;
521	image->height = h;
522
523	return (image);
524}
525
526static DEF_BI_SPM(Create3DDotImage)
527{
528	Image *image;
529	int   h;
530	static int idepth = 2;
531
532	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
533	if(!(h & 1)) {
534		h--;
535	}
536
537	image = AllocImage();
538	if(! image) {
539		return (None);
540	}
541	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
542	if(image->pixmap == None) {
543		free(image);
544		return (None);
545	}
546
547	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
548	             off, true, false);
549	Draw3DBorder(image->pixmap, (h / 2) - idepth,
550	             (h / 2) - idepth,
551	             2 * idepth + 1,
552	             2 * idepth + 1,
553	             idepth, cp, off, true, false);
554	image->width  = h;
555	image->height = h;
556	return (image);
557}
558
559static DEF_BI_SPM(Create3DBarImage)
560{
561	Image *image;
562	int   h;
563	static int idepth = 2;
564
565	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
566	if(!(h & 1)) {
567		h--;
568	}
569
570	image = AllocImage();
571	if(! image) {
572		return (None);
573	}
574	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
575	if(image->pixmap == None) {
576		free(image);
577		return (None);
578	}
579
580	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
581	             off, true, false);
582	Draw3DBorder(image->pixmap,
583	             Scr->TitleButtonShadowDepth + 2,
584	             (h / 2) - idepth,
585	             h - 2 * (Scr->TitleButtonShadowDepth + 2),
586	             2 * idepth + 1,
587	             idepth, cp, off, true, false);
588	image->width  = h;
589	image->height = h;
590	return (image);
591}
592
593static DEF_BI_SPM(Create3DVertBarImage)
594{
595	Image *image;
596	int   h;
597	static int idepth = 2;
598
599	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
600	if(!(h & 1)) {
601		h--;
602	}
603
604	image = AllocImage();
605	if(! image) {
606		return (None);
607	}
608	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
609	if(image->pixmap == None) {
610		free(image);
611		return (None);
612	}
613
614	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
615	             off, true, false);
616	Draw3DBorder(image->pixmap,
617	             (h / 2) - idepth,
618	             Scr->TitleButtonShadowDepth + 2,
619	             2 * idepth + 1,
620	             h - 2 * (Scr->TitleButtonShadowDepth + 2),
621	             idepth, cp, off, true, false);
622	image->width  = h;
623	image->height = h;
624	return (image);
625}
626
627static DEF_BI_SPM(Create3DMenuImage)
628{
629	Image *image;
630	int   h, i;
631
632	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
633	if(!(h & 1)) {
634		h--;
635	}
636
637	image = AllocImage();
638	if(! image) {
639		return (None);
640	}
641	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
642	if(image->pixmap == None) {
643		free(image);
644		return (None);
645	}
646
647	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
648	             off, true, false);
649	for(i = 4; i < h - 7; i += 5) {
650		Draw3DBorder(image->pixmap, 4, i, h - 8, 4, 2, cp, off, true, false);
651	}
652	image->width  = h;
653	image->height = h;
654	return (image);
655}
656
657static DEF_BI_SPM(Create3DResizeImage)
658{
659	Image *image;
660	int   h;
661
662	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
663	if(!(h & 1)) {
664		h--;
665	}
666
667	image = AllocImage();
668	if(! image) {
669		return (None);
670	}
671	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
672	if(image->pixmap == None) {
673		free(image);
674		return (None);
675	}
676
677	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
678	             off, true, false);
679	Draw3DBorder(image->pixmap, 0, h / 4, ((3 * h) / 4) + 1, ((3 * h) / 4) + 1,
680	             2, cp, off, true, false);
681	Draw3DBorder(image->pixmap, 0, h / 2, (h / 2) + 1, (h / 2) + 1, 2, cp, off,
682	             true, false);
683	image->width  = h;
684	image->height = h;
685	return (image);
686}
687
688static DEF_BI_SPM(Create3DZoomImage)
689{
690	Image *image;
691	int         h;
692	static int idepth = 2;
693
694	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
695	if(!(h & 1)) {
696		h--;
697	}
698
699	image = AllocImage();
700	if(! image) {
701		return (None);
702	}
703	image->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
704	if(image->pixmap == None) {
705		free(image);
706		return (None);
707	}
708
709	Draw3DBorder(image->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
710	             off, true, false);
711	Draw3DBorder(image->pixmap, Scr->TitleButtonShadowDepth + 2,
712	             Scr->TitleButtonShadowDepth + 2,
713	             h - 2 * (Scr->TitleButtonShadowDepth + 2),
714	             h - 2 * (Scr->TitleButtonShadowDepth + 2),
715	             idepth, cp, off, true, false);
716
717	image->width  = h;
718	image->height = h;
719	return (image);
720}
721
722#undef DEF_BI_SPM
723
724
725
726/*
727 * And the animated builtins.  These are the ones specified with names
728 * like "%xpm:resize".
729 *
730 * These yield [ctwm struct] Image's.
731 */
732#define DEF_BI_ASPM(nm) Image *nm(ColorPair cp)
733
734/* Backend generators */
735static Image *Create3DResizeAnimation(bool in, bool left, bool top,
736                                      ColorPair cp);
737static Image *Create3DMenuAnimation(bool up, ColorPair cp);
738static Image *Create3DZoomAnimation(bool in, bool out, int n, ColorPair cp);
739
740/* Frontends */
741/* Using: ResizeAnimation */
742static DEF_BI_ASPM(Create3DResizeInTopAnimation);
743static DEF_BI_ASPM(Create3DResizeOutTopAnimation);
744static DEF_BI_ASPM(Create3DResizeInBotAnimation);
745static DEF_BI_ASPM(Create3DResizeOutBotAnimation);
746/* Using: MenuAnimation */
747static DEF_BI_ASPM(Create3DMenuUpAnimation);
748static DEF_BI_ASPM(Create3DMenuDownAnimation);
749/* Using: ZoomAnimation */
750static DEF_BI_ASPM(Create3DMazeOutAnimation);
751static DEF_BI_ASPM(Create3DMazeInAnimation);
752static DEF_BI_ASPM(Create3DZoomInAnimation);
753static DEF_BI_ASPM(Create3DZoomOutAnimation);
754static DEF_BI_ASPM(Create3DZoomInOutAnimation);
755
756
757/*
758 * Entry for animated pixmaps
759 *
760 * This is where we find "%xpm:something".  Note that as above, these are
761 * _not_ XPM's, and have no relation to the configurable XPM support,
762 * which we get with images specified as "xpm:something" (no leading
763 * colon).  Still not confusing at _all_.
764 */
765Image *
766get_builtin_animated_pixmap(const char *name, ColorPair cp)
767{
768	int    i;
769	static struct {
770		char *name;
771		DEF_BI_ASPM((*proc));
772	} pmtab[] = {
773		/* Lookup for "%xpm:" pixmaps */
774		{ "%xpm:resize-out-top", Create3DResizeInTopAnimation },
775		{ "%xpm:resize-in-top",  Create3DResizeOutTopAnimation },
776		{ "%xpm:resize-out-bot", Create3DResizeInBotAnimation },
777		{ "%xpm:resize-in-bot",  Create3DResizeOutBotAnimation },
778		{ "%xpm:menu-up",        Create3DMenuUpAnimation },
779		{ "%xpm:menu-down",      Create3DMenuDownAnimation },
780		{ "%xpm:maze-out",       Create3DMazeOutAnimation },
781		{ "%xpm:maze-in",        Create3DMazeInAnimation },
782		{ "%xpm:resize",         Create3DZoomOutAnimation }, // compat
783		{ "%xpm:zoom-out",       Create3DZoomOutAnimation },
784		{ "%xpm:zoom-in",        Create3DZoomInAnimation },
785		{ "%xpm:zoom-inout",     Create3DZoomInOutAnimation },
786	};
787
788	/* Seatbelts */
789	if(!name || (strncmp(name, "%xpm:", 5) != 0)) {
790		return NULL;
791	}
792
793	for(i = 0; i < (sizeof pmtab) / (sizeof pmtab[0]); i++) {
794		if(strcasecmp(pmtab[i].name, name) == 0) {
795			Image *image = (*pmtab[i].proc)(cp);
796			if(image == NULL) {
797				fprintf(stderr, "%s:  unable to build pixmap \"%s\"\n",
798				        ProgramName, name);
799				return NULL;
800			}
801			return image;
802		}
803	}
804
805	fprintf(stderr, "%s:  no such built-in pixmap \"%s\"\n", ProgramName, name);
806	return (None);
807}
808
809
810/*
811 * First a couple generator functions the actual functions use
812 */
813static Image *
814Create3DResizeAnimation(bool in, bool left, bool top,
815                        ColorPair cp)
816{
817	int         h, i, j;
818	Image       *image, *im, *im1;
819
820	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
821	if(!(h & 1)) {
822		h--;
823	}
824
825	image = im1 = NULL;
826	for(i = (in ? 0 : (h / 4) - 1); (i < h / 4) && (i >= 0); i += (in ? 1 : -1)) {
827		im = AllocImage();
828		if(! im) {
829			return NULL;
830		}
831		im->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
832		if(im->pixmap == None) {
833			free(im);
834			return NULL;
835		}
836		Draw3DBorder(im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
837		             off, true, false);
838		for(j = i; j <= h; j += (h / 4)) {
839			Draw3DBorder(im->pixmap, (left ? 0 : j), (top ? 0 : j),
840			             h - j, h - j, 2, cp, off, true, false);
841		}
842		im->mask   = None;
843		im->width  = h;
844		im->height = h;
845		im->next   = NULL;
846		if(image == NULL) {
847			image = im1 = im;
848		}
849		else {
850			im1->next = im;
851			im1 = im;
852		}
853	}
854	if(im1 != None) {
855		im1->next = image;
856	}
857	return image;
858}
859
860static Image *
861Create3DMenuAnimation(bool up, ColorPair cp)
862{
863	int   h, i, j;
864	Image *image, *im, *im1;
865
866	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
867	if(!(h & 1)) {
868		h--;
869	}
870
871	image = im1 = NULL;
872	for(j = (up ? 4 : 0); j != (up ? -1 : 5); j += (up ? -1 : 1)) {
873		im = AllocImage();
874		if(! im) {
875			return NULL;
876		}
877		im->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
878		if(im->pixmap == None) {
879			free(im);
880			return NULL;
881		}
882		Draw3DBorder(im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth, cp,
883		             off, true, false);
884		for(i = j; i < h - 3; i += 5) {
885			Draw3DBorder(im->pixmap, 4, i, h - 8, 4, 2, cp, off, true, false);
886		}
887		im->mask   = None;
888		im->width  = h;
889		im->height = h;
890		im->next   = NULL;
891		if(image == NULL) {
892			image = im1 = im;
893		}
894		else {
895			im1->next = im;
896			im1 = im;
897		}
898	}
899	if(im1 != None) {
900		im1->next = image;
901	}
902	return image;
903}
904
905static Image *
906Create3DZoomAnimation(bool in, bool out, int n, ColorPair cp)
907{
908	int         h, i, j, k;
909	Image       *image, *im, *im1;
910
911	h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
912	if(!(h & 1)) {
913		h--;
914	}
915
916	if(n == 0) {
917		n = (h / 2) - 2;
918	}
919
920	image = im1 = NULL;
921	for(j = (out ? -1 : 1) ; j < (in ? 2 : 0); j += 2) {
922		for(k = (j > 0 ? 0 : n - 1) ; (k >= 0) && (k < n); k += j) {
923			im = AllocImage();
924			im->pixmap = XCreatePixmap(dpy, Scr->Root, h, h, Scr->d_depth);
925			Draw3DBorder(im->pixmap, 0, 0, h, h, Scr->TitleButtonShadowDepth,
926			             cp, off, true, false);
927			for(i = 2 + k; i < (h / 2); i += n) {
928				Draw3DBorder(im->pixmap, i, i, h - (2 * i), h - (2 * i), 2, cp,
929				             off, true, false);
930			}
931			im->mask   = None;
932			im->width  = h;
933			im->height = h;
934			im->next   = NULL;
935			if(image == NULL) {
936				image = im1 = im;
937			}
938			else {
939				im1->next = im;
940				im1 = im;
941			}
942		}
943	}
944	if(im1 != None) {
945		im1->next = image;
946	}
947	return image;
948}
949
950
951/*
952 * And the wrapper funcs for making the images
953 */
954static DEF_BI_ASPM(Create3DResizeInTopAnimation)
955{
956	return Create3DResizeAnimation(true, false, true, cp);
957}
958
959static DEF_BI_ASPM(Create3DResizeOutTopAnimation)
960{
961	return Create3DResizeAnimation(false, false, true, cp);
962}
963
964static DEF_BI_ASPM(Create3DResizeInBotAnimation)
965{
966	return Create3DResizeAnimation(true, true, false, cp);
967}
968
969static DEF_BI_ASPM(Create3DResizeOutBotAnimation)
970{
971	return Create3DResizeAnimation(false, true, false, cp);
972}
973
974
975static DEF_BI_ASPM(Create3DMenuUpAnimation)
976{
977	return Create3DMenuAnimation(true, cp);
978}
979
980static DEF_BI_ASPM(Create3DMenuDownAnimation)
981{
982	return Create3DMenuAnimation(false, cp);
983}
984
985
986static DEF_BI_ASPM(Create3DMazeInAnimation)
987{
988	return Create3DZoomAnimation(true, false, 6, cp);
989}
990
991static DEF_BI_ASPM(Create3DMazeOutAnimation)
992{
993	return Create3DZoomAnimation(false, true, 6, cp);
994}
995
996static DEF_BI_ASPM(Create3DZoomInAnimation)
997{
998	return Create3DZoomAnimation(true, false, 0, cp);
999}
1000
1001static DEF_BI_ASPM(Create3DZoomOutAnimation)
1002{
1003	return Create3DZoomAnimation(false, true, 0, cp);
1004}
1005
1006static DEF_BI_ASPM(Create3DZoomInOutAnimation)
1007{
1008	return Create3DZoomAnimation(true, true, 0, cp);
1009}
1010
1011#undef DEF_BI_ASPM
1012
1013
1014/*
1015 * Lastly, some gray/black pixmaps that are used in window border and
1016 * hilite bars.
1017 */
1018#define BG_WIDTH  2
1019#define BG_HEIGHT 2
1020
1021Pixmap
1022mk_blackgray_pixmap(const char *which, Drawable dw,
1023                    unsigned long fg, unsigned long bg)
1024{
1025	unsigned char gray_bits[]  = { 0x02, 0x01 };
1026	unsigned char black_bits[] = { 0xFF, 0xFF };
1027	char *bits;
1028
1029	/* Which are we asking for? */
1030	if(strcmp(which, "black") == 0) {
1031		bits = (char *)black_bits;
1032	}
1033	else if(strcmp(which, "gray") == 0) {
1034		bits = (char *)gray_bits;
1035	}
1036	else {
1037		fprintf(stderr, "%s(): Invalid which arg '%s'\n", __func__, which);
1038		return None;
1039	}
1040
1041	/* Make it */
1042	return XCreatePixmapFromBitmapData(dpy, dw,
1043	                                   bits, BG_WIDTH, BG_HEIGHT,
1044	                                   fg, bg, Scr->d_depth);
1045}
1046
1047void
1048get_blackgray_size(int *width, int *height)
1049{
1050	if(width) {
1051		*width  = BG_WIDTH;
1052	}
1053	if(height) {
1054		*height = BG_HEIGHT;
1055	}
1056}
1057
1058#undef BG_HEIGHT
1059#undef BG_WIDTH
1060