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)
27 static DEF_BI_PPM(CreateXLogoPixmap);
28 static DEF_BI_PPM(CreateResizePixmap);
29 static DEF_BI_PPM(CreateQuestionPixmap);
30 static DEF_BI_PPM(CreateMenuPixmap);
31 static 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  */
42 Pixmap
get_builtin_plain_pixmap(const char * name,unsigned int * widthp,unsigned int * heightp)43 get_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  */
DEF_BI_PPM(CreateXLogoPixmap)93 DEF_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 
DEF_BI_PPM(CreateResizePixmap)129 DEF_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
188 static char questionmark_bits[] = {
189 	0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18
190 };
191 
DEF_BI_PPM(CreateQuestionPixmap)192 DEF_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 
DEF_BI_PPM(CreateMenuPixmap)211 DEF_BI_PPM(CreateMenuPixmap)
212 {
213 	return (CreateMenuIcon(Scr->TBInfo.width - Scr->TBInfo.border * 2, widthp,
214 	                       heightp));
215 }
216 
DEF_BI_PPM(CreateDotPixmap)217 DEF_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)
258 static DEF_BI_SPM(Create3DMenuImage);
259 static DEF_BI_SPM(Create3DDotImage);
260 static DEF_BI_SPM(Create3DResizeImage);
261 static DEF_BI_SPM(Create3DZoomImage);
262 static DEF_BI_SPM(Create3DBarImage);
263 static DEF_BI_SPM(Create3DVertBarImage);
264 static DEF_BI_SPM(Create3DCrossImage);
265 static DEF_BI_SPM(Create3DIconifyImage);
266 static DEF_BI_SPM(Create3DSunkenResizeImage);
267 static 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  */
278 Image *
get_builtin_scalable_pixmap(const char * name,ColorPair cp)279 get_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
DEF_BI_SPM(Create3DCrossImage)323 static 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 
DEF_BI_SPM(Create3DIconifyImage)421 static 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 
DEF_BI_SPM(Create3DSunkenResizeImage)461 static 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 
DEF_BI_SPM(Create3DBoxImage)495 static 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 
DEF_BI_SPM(Create3DDotImage)526 static 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 
DEF_BI_SPM(Create3DBarImage)559 static 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 
DEF_BI_SPM(Create3DVertBarImage)593 static 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 
DEF_BI_SPM(Create3DMenuImage)627 static 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 
DEF_BI_SPM(Create3DResizeImage)657 static 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 
DEF_BI_SPM(Create3DZoomImage)688 static 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 */
735 static Image *Create3DResizeAnimation(bool in, bool left, bool top,
736                                       ColorPair cp);
737 static Image *Create3DMenuAnimation(bool up, ColorPair cp);
738 static Image *Create3DZoomAnimation(bool in, bool out, int n, ColorPair cp);
739 
740 /* Frontends */
741 /* Using: ResizeAnimation */
742 static DEF_BI_ASPM(Create3DResizeInTopAnimation);
743 static DEF_BI_ASPM(Create3DResizeOutTopAnimation);
744 static DEF_BI_ASPM(Create3DResizeInBotAnimation);
745 static DEF_BI_ASPM(Create3DResizeOutBotAnimation);
746 /* Using: MenuAnimation */
747 static DEF_BI_ASPM(Create3DMenuUpAnimation);
748 static DEF_BI_ASPM(Create3DMenuDownAnimation);
749 /* Using: ZoomAnimation */
750 static DEF_BI_ASPM(Create3DMazeOutAnimation);
751 static DEF_BI_ASPM(Create3DMazeInAnimation);
752 static DEF_BI_ASPM(Create3DZoomInAnimation);
753 static DEF_BI_ASPM(Create3DZoomOutAnimation);
754 static 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  */
765 Image *
get_builtin_animated_pixmap(const char * name,ColorPair cp)766 get_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  */
813 static Image *
Create3DResizeAnimation(bool in,bool left,bool top,ColorPair cp)814 Create3DResizeAnimation(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 
860 static Image *
Create3DMenuAnimation(bool up,ColorPair cp)861 Create3DMenuAnimation(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 
905 static Image *
Create3DZoomAnimation(bool in,bool out,int n,ColorPair cp)906 Create3DZoomAnimation(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  */
DEF_BI_ASPM(Create3DResizeInTopAnimation)954 static DEF_BI_ASPM(Create3DResizeInTopAnimation)
955 {
956 	return Create3DResizeAnimation(true, false, true, cp);
957 }
958 
DEF_BI_ASPM(Create3DResizeOutTopAnimation)959 static DEF_BI_ASPM(Create3DResizeOutTopAnimation)
960 {
961 	return Create3DResizeAnimation(false, false, true, cp);
962 }
963 
DEF_BI_ASPM(Create3DResizeInBotAnimation)964 static DEF_BI_ASPM(Create3DResizeInBotAnimation)
965 {
966 	return Create3DResizeAnimation(true, true, false, cp);
967 }
968 
DEF_BI_ASPM(Create3DResizeOutBotAnimation)969 static DEF_BI_ASPM(Create3DResizeOutBotAnimation)
970 {
971 	return Create3DResizeAnimation(false, true, false, cp);
972 }
973 
974 
DEF_BI_ASPM(Create3DMenuUpAnimation)975 static DEF_BI_ASPM(Create3DMenuUpAnimation)
976 {
977 	return Create3DMenuAnimation(true, cp);
978 }
979 
DEF_BI_ASPM(Create3DMenuDownAnimation)980 static DEF_BI_ASPM(Create3DMenuDownAnimation)
981 {
982 	return Create3DMenuAnimation(false, cp);
983 }
984 
985 
DEF_BI_ASPM(Create3DMazeInAnimation)986 static DEF_BI_ASPM(Create3DMazeInAnimation)
987 {
988 	return Create3DZoomAnimation(true, false, 6, cp);
989 }
990 
DEF_BI_ASPM(Create3DMazeOutAnimation)991 static DEF_BI_ASPM(Create3DMazeOutAnimation)
992 {
993 	return Create3DZoomAnimation(false, true, 6, cp);
994 }
995 
DEF_BI_ASPM(Create3DZoomInAnimation)996 static DEF_BI_ASPM(Create3DZoomInAnimation)
997 {
998 	return Create3DZoomAnimation(true, false, 0, cp);
999 }
1000 
DEF_BI_ASPM(Create3DZoomOutAnimation)1001 static DEF_BI_ASPM(Create3DZoomOutAnimation)
1002 {
1003 	return Create3DZoomAnimation(false, true, 0, cp);
1004 }
1005 
DEF_BI_ASPM(Create3DZoomInOutAnimation)1006 static 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 
1021 Pixmap
mk_blackgray_pixmap(const char * which,Drawable dw,unsigned long fg,unsigned long bg)1022 mk_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 
1047 void
get_blackgray_size(int * width,int * height)1048 get_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