1 /*
2  * Copyright (c) 2002 Sasha Vasko <sasha@aftercode.net>
3  * Copyright (c) 1998, 1999 Ethan Fischer <allanon@crystaltokyo.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20 
21 #include "../configure.h"
22 
23 #undef LOCAL_DEBUG
24 #include "asapp.h"
25 #include "afterstep.h"
26 #include "parser.h"
27 #include "mystyle.h"
28 #include "screen.h"
29 #include "../libAfterImage/afterimage.h"
30 
31 static char *DefaultMyStyleName = "default";
32 
33 
mystyle_free_back_icon(MyStyle * style)34 void mystyle_free_back_icon (MyStyle * style)
35 {
36 	if (!get_flags (style->inherit_flags, F_BACKPIXMAP)) {
37 		if (get_flags (style->user_flags, F_EXTERNAL_BACKPIX))
38 			style->back_icon.pix = None;
39 		if (get_flags (style->user_flags, F_EXTERNAL_BACKMASK)) {
40 			style->back_icon.mask = None;
41 			style->back_icon.alpha = None;
42 		}
43 
44 		free_icon_resources (&(style->back_icon));
45 	}
46 	memset (&(style->back_icon), 0x00, sizeof (style->back_icon));
47 }
48 
49 /* just a nice error printing function */
mystyle_error(char * format,char * name,char * text2)50 void mystyle_error (char *format, char *name, char *text2)
51 {
52 	if (text2)
53 		show_error ("MyStyle [%s] parsing error: %s %s", name, format, text2);
54 	else
55 		show_error ("MyStyle [%s] parsing error: %s", name, format);
56 }
57 
58 /* Creates tinting GC for drawable d, with color tintColor,
59    using color combining function function */
CreateTintGC(Drawable d,unsigned long tintColor,int function)60 GC CreateTintGC (Drawable d, unsigned long tintColor, int function)
61 {
62 	XGCValues gcvalue;
63 
64 	if (tintColor == None || d == None)
65 		return None;
66 
67 	gcvalue.function = function;
68 	gcvalue.foreground = tintColor;
69 	gcvalue.background = tintColor;
70 	return XCreateGC (dpy, d, GCFunction | GCForeground | GCBackground,
71 										&gcvalue);
72 }
73 
make_component_hilite(int cmp)74 CARD8 make_component_hilite (int cmp)
75 {
76 	if (cmp < 51)
77 		cmp = 51;
78 	cmp = (cmp * 12) / 10;
79 	return (cmp > 255) ? 255 : cmp;
80 }
81 
82 /* This routine computes the hilite color from the background color */
GetHilite(ARGB32 background)83 inline ARGB32 GetHilite (ARGB32 background)
84 {
85 	CARD32 a = make_component_hilite (ARGB32_ALPHA8 (background));
86 	CARD32 r = make_component_hilite (ARGB32_RED8 (background));
87 	CARD32 g = make_component_hilite (ARGB32_GREEN8 (background));
88 	CARD32 b = make_component_hilite (ARGB32_BLUE8 (background));
89 
90 	return MAKE_ARGB32 (a, r, g, b);
91 }
92 
93 /* This routine computes the shadow color from the background color */
GetShadow(ARGB32 background)94 inline ARGB32 GetShadow (ARGB32 background)
95 {
96 	CARD16 a, r, g, b;
97 
98 	a = (ARGB32_ALPHA8 (background)) * 3 / 4;
99 	r = (ARGB32_RED8 (background)) * 3 / 4;
100 	g = (ARGB32_GREEN8 (background)) * 3 / 4;
101 	b = (ARGB32_BLUE8 (background)) * 3 / 4;
102 
103 	return MAKE_ARGB32 (a, r, g, b);
104 }
105 
GetAverage(ARGB32 foreground,ARGB32 background)106 inline ARGB32 GetAverage (ARGB32 foreground, ARGB32 background)
107 {
108 	CARD16 a, r, g, b;
109 
110 	a = (ARGB32_ALPHA8 (foreground) + ARGB32_ALPHA8 (background)) / 2;
111 	r = (ARGB32_RED8 (foreground) + ARGB32_RED8 (background)) / 2;
112 	g = (ARGB32_GREEN8 (foreground) + ARGB32_GREEN8 (background)) / 2;
113 	b = (ARGB32_BLUE8 (foreground) + ARGB32_BLUE8 (background)) / 2;
114 	return MAKE_ARGB32 (a, r, g, b);
115 }
116 
117 /* create the default style if necessary, and fill in the unset fields
118  * of the other styles from the default */
mystyle_list_fix_styles(ASHashTable * list)119 void mystyle_list_fix_styles (ASHashTable * list)
120 {
121 	MyStyle *dflt;
122 	MyStyle *style;
123 	ASHashIterator iterator;
124 
125 	if (list == NULL)
126 		if ((list = ASDefaultScr->Look.styles_list) == NULL)
127 			return;
128 
129 /*
130  * the user may not have set the default style, so set it here
131  * all we need are reasonable defaults, and most defaults have been set
132  *  by mystyle_new() already
133  * we need FONT, FORECOLOR, and BACKCOLOR, at a minimum
134  */
135 	if ((dflt = mystyle_list_find (list, DefaultMyStyleName)) == NULL)
136 		dflt = mystyle_list_new (list, DefaultMyStyleName);
137 	if ((dflt->set_flags & F_FORECOLOR) == 0)
138 		dflt->user_flags |= F_FORECOLOR;
139 	if ((dflt->set_flags & F_BACKCOLOR) == 0) {
140 		dflt->relief.fore = GetHilite (dflt->colors.back);
141 		dflt->relief.back = GetShadow (dflt->colors.back);
142 		dflt->user_flags |= F_BACKCOLOR;
143 	}
144 	if ((dflt->set_flags & F_FONT) == 0) {
145 		if (load_font (NULL, &dflt->font) == False) {
146 			show_error ("couldn't load the default font");
147 			exit (1);
148 		}
149 		dflt->user_flags |= F_FONT;
150 	}
151 	dflt->set_flags = dflt->inherit_flags | dflt->user_flags;
152 
153 /* fix up the styles, using the default style */
154 	if (start_hash_iteration (list, &iterator))
155 		do {
156 			Bool transparent = False;
157 
158 			style = (MyStyle *) curr_hash_data (&iterator);
159 			if (style != dflt)
160 				mystyle_merge_styles (dflt, style, False, False);
161 			if (style->texture_type == TEXTURE_SHAPED_SCALED_PIXMAP ||
162 					style->texture_type == TEXTURE_SHAPED_PIXMAP
163 					|| style->texture_type > TEXTURE_PIXMAP) {
164 				transparent = True;
165 			} else if (style->texture_type >= TEXTURE_GRADIENT_START
166 								 && style->texture_type <= TEXTURE_GRADIENT_END) {
167 				/* need to check if any of the gradient colors has alpha channel < 0xff */
168 				int i = style->gradient.npoints;
169 
170 				while (--i >= 0)
171 					if (ARGB32_ALPHA8 (style->gradient.color[i]) < 0x00F0) {
172 						transparent = True;
173 						break;
174 					}
175 			}
176 			if (transparent) {
177 				set_flags (style->user_flags, F_TRANSPARENT);
178 				set_flags (style->set_flags, F_TRANSPARENT);
179 			}
180 		}
181 		while (next_hash_item (&iterator));
182 }
183 
mystyle_fix_styles(void)184 void mystyle_fix_styles (void)
185 {
186 	mystyle_list_fix_styles (NULL);
187 }
188 
mystyle_translate_grad_type(int type)189 int mystyle_translate_grad_type (int type)
190 {
191 	switch (type) {
192 	case TEXTURE_GRADIENT:
193 		return GRADIENT_TopLeft2BottomRight;
194 
195 	case TEXTURE_HGRADIENT:
196 	case TEXTURE_HCGRADIENT:
197 		return GRADIENT_Left2Right;
198 
199 	case TEXTURE_VGRADIENT:
200 	case TEXTURE_VCGRADIENT:
201 		return GRADIENT_Top2Bottom;
202 	case TEXTURE_GRADIENT_TL2BR:
203 		return GRADIENT_TopLeft2BottomRight;
204 	case TEXTURE_GRADIENT_BL2TR:
205 		return GRADIENT_BottomLeft2TopRight;
206 	case TEXTURE_GRADIENT_T2B:
207 		return GRADIENT_Top2Bottom;
208 	case TEXTURE_GRADIENT_L2R:
209 		return GRADIENT_Left2Right;
210 	default:
211 		return -1;
212 	}
213 }
214 
215 /****************************************************************************
216  * grab a section of the screen and darken it
217  ***************************************************************************/
grab_root_asimage(ScreenInfo * scr,Window target,Bool screenshot)218 ASImage *grab_root_asimage (ScreenInfo * scr, Window target,
219 														Bool screenshot)
220 {
221 	XSetWindowAttributes attr;
222 	XEvent event;
223 	int tick_count = 0;
224 	Window src;
225 	ASImage *root_im = NULL;
226 	int x = scr->RootClipArea.x, y = scr->RootClipArea.y;
227 	int width = scr->RootClipArea.width, height = scr->RootClipArea.height;
228 
229 	if (scr == NULL)
230 		scr = ASDefaultScr;
231 	/* this only works if we use DefaultVisual - same visual as the Root window : */
232 	if (scr->asv->visual_info.visual !=
233 			DefaultVisual (dpy, DefaultScreen (dpy)))
234 		return NULL;
235 
236 	if (target != None && target != scr->Root) {
237 		Window wdumm;
238 		unsigned int udumm;
239 		unsigned int bw = 0;
240 		int tx, ty;
241 		unsigned int tw, th;
242 
243 		if (XGetGeometry (dpy, target, &wdumm, &tx, &ty, &tw, &th, &bw, &udumm)
244 				!= 0) {
245 			/* we need root window position : */
246 			XTranslateCoordinates (dpy, target, scr->Root, 0, 0, &tx, &ty,
247 														 &wdumm);
248 			x = tx - bw;
249 			y = ty - bw;
250 			width = tw + bw + bw;
251 			height = th + bw + bw;
252 		}
253 	}
254 
255 	if (x < 0) {
256 		width += x;
257 		x = 0;
258 	}
259 	if (y < 0) {
260 		height += y;
261 		y = 0;
262 	}
263 	if (x + width > ASDefaultScrWidth)
264 		width = (int)(ASDefaultScrWidth) - x;
265 	if (y + height > ASDefaultScrHeight)
266 		height = (int)(ASDefaultScrHeight) - y;
267 
268 	if (height < 0 || width < 0)
269 		return NULL;
270 
271 	attr.background_pixmap = screenshot ? None : ParentRelative;
272 	attr.backing_store = NotUseful;
273 	attr.event_mask = ExposureMask;
274 	attr.override_redirect = True;
275 
276 	LOCAL_DEBUG_OUT ("grabbing root image from %dx%d%+d%+d", width, height,
277 									 x, y);
278 
279 	src =
280 			create_visual_window (scr->asv, scr->Root, x, y, width, height, 0,
281 														CopyFromParent,
282 														CWBackPixmap | CWBackingStore |
283 														CWOverrideRedirect | CWEventMask, &attr);
284 
285 	if (src == None)
286 		return NULL;
287 	grab_server ();
288 	XMapRaised (dpy, src);
289 	XSync (dpy, False);
290 	start_ticker (1);
291 	/* now we have to wait for our window to become mapped - waiting for Expose */
292 	for (tick_count = 0; !XCheckWindowEvent (dpy, src, ExposureMask, &event)
293 			 && tick_count < 100; tick_count++)
294 		/*sleep_a_millisec(500); */
295 		wait_tick ();
296 	if (tick_count < 100)
297 		if ((root_im =
298 				 pixmap2asimage (scr->asv, src, 0, 0, width, height, AllPlanes,
299 												 False, 100)) != NULL) {
300 			if ((scr->RootClipArea.y < 0 || scr->RootClipArea.y < 0)
301 					&& !screenshot) {
302 				ASImage *tmp;
303 
304 				x = (scr->RootClipArea.x < 0) ? -scr->RootClipArea.x : 0;
305 				y = (scr->RootClipArea.y < 0) ? -scr->RootClipArea.y : 0;
306 
307 				tmp = tile_asimage (scr->asv, root_im,
308 														x, y, scr->RootClipArea.width,
309 														scr->RootClipArea.height, TINT_NONE,
310 														ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
311 				if (tmp) {
312 					destroy_asimage (&root_im);
313 					root_im = tmp;
314 				}
315 			}
316 		}
317 	XDestroyWindow (dpy, src);
318 	ungrab_server ();
319 	return root_im;
320 }
321 
322 
323 
324 static merge_scanlines_func mystyle_merge_scanlines_func_xref[] = {
325 	allanon_scanlines,
326 	alphablend_scanlines,
327 	add_scanlines,
328 	colorize_scanlines,
329 	darken_scanlines,
330 	diff_scanlines,
331 	dissipate_scanlines,
332 	hue_scanlines,
333 	lighten_scanlines,
334 	overlay_scanlines,
335 	saturate_scanlines,
336 	screen_scanlines,
337 	sub_scanlines,
338 	tint_scanlines,
339 	value_scanlines,
340 	/* just a filler below : */
341 	alphablend_scanlines,
342 	alphablend_scanlines,
343 	alphablend_scanlines,
344 	NULL
345 };
346 
mystyle_translate_texture_type(int texture_type)347 merge_scanlines_func mystyle_translate_texture_type (int texture_type)
348 {
349 	register int index = 1;				/* default is alphablending */
350 
351 	if (texture_type >= TEXTURE_SCALED_TRANSPIXMAP
352 			&& texture_type < TEXTURE_SCALED_TRANSPIXMAP_END)
353 		index = texture_type - TEXTURE_SCALED_TRANSPIXMAP;
354 	else if (texture_type >= TEXTURE_TRANSPIXMAP
355 					 && texture_type < TEXTURE_TRANSPIXMAP_END)
356 		index = texture_type - TEXTURE_TRANSPIXMAP;
357 	return mystyle_merge_scanlines_func_xref[index];
358 }
359 
mystyle_flip_image(ASImage * im,int width,int height,int flip)360 static inline ASImage *mystyle_flip_image (ASImage * im, int width,
361 																					 int height, int flip)
362 {
363 	ASImage *tmp;
364 
365 	if (flip == 0)
366 		return im;
367 	tmp =
368 			flip_asimage (ASDefaultVisual, im, 0, 0, width, height, flip,
369 										ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT);
370 	if (tmp != NULL) {
371 		safe_asimage_destroy (im);
372 		im = tmp;
373 	}
374 	return im;
375 }
376 
clip_root_pixmap(Pixmap root_pixmap,int width,int height)377 static ASImage *clip_root_pixmap (Pixmap root_pixmap, int width,
378 																	int height)
379 {
380 	ASImage *result = NULL;
381 	XRectangle *clip_area = &(ASDefaultScr->RootClipArea);
382 
383 	if (root_pixmap) {
384 		ASImage *tmp_root;
385 		int root_x = 0, root_y = 0;
386 		int clip_x = clip_area->x;
387 		int clip_y = clip_area->y;
388 
389 		while (clip_x < 0)
390 			clip_x += ASDefaultScrWidth;
391 		clip_x %= width;
392 		while (clip_y < 0)
393 			clip_y += ASDefaultScrHeight;
394 		clip_y %= height;
395 
396 		/* at this point clip_x and clip_y fall into root pixmap */
397 
398 		if (clip_x + clip_area->width <= width) {
399 			root_x = clip_x;
400 			width = clip_area->width;
401 		}
402 		if (clip_y + clip_area->height <= height) {
403 			root_y = clip_y;
404 			height = clip_area->height;
405 		}
406 		/* fprintf( stderr, "RootPixmap2RootImage %dx%d%+d%+d", root_w, root_h, root_x,
407 		   root_y); */
408 		tmp_root =
409 				pixmap2asimage (ASDefaultVisual, root_pixmap, root_x, root_y,
410 												width, height, AllPlanes, False, 100);
411 
412 		LOCAL_DEBUG_OUT ("Root pixmap ASImage = %p, size = %dx%d", tmp_root,
413 										 tmp_root ? tmp_root->width : 0,
414 										 tmp_root ? tmp_root->height : 0);
415 		if (tmp_root) {
416 			if (clip_x == root_x && clip_y == root_y && clip_area->width == width
417 					&& clip_area->height == height) {
418 				result = tmp_root;
419 			} else {
420 				result = tile_asimage (ASDefaultVisual, tmp_root,
421 															 (clip_x == root_x) ? 0 : clip_area->x,
422 															 (clip_y == root_y) ? 0 : clip_area->y,
423 															 clip_area->width, clip_area->height,
424 															 TINT_NONE, ASA_ASImage, 100,
425 															 ASIMAGE_QUALITY_DEFAULT);
426 				destroy_asimage (&tmp_root);
427 			}
428 		}
429 	}
430 	return result;
431 }
432 
mystyle_make_image_int(MyStyle * style,int root_x,int root_y,int crop_x,int crop_y,int crop_width,int crop_height,int scale_width,int scale_height,int flip,ASImage * underlayment,int overlay_type)433 static ASImage *mystyle_make_image_int (MyStyle * style, int root_x,
434 																				int root_y, int crop_x, int crop_y,
435 																				int crop_width, int crop_height,
436 																				int scale_width, int scale_height,
437 																				int flip, ASImage * underlayment,
438 																				int overlay_type)
439 {
440 	ASImage *im = NULL;
441 	Pixmap root_pixmap;
442 	Bool transparency = TransparentMS (style);
443 	int preflip_width, preflip_height;
444 	int width, height;
445 
446 	if (underlayment) {
447 		if (overlay_type >= TEXTURE_SCALED_TRANSPIXMAP)
448 			overlay_type =
449 					TEXTURE_TRANSPIXMAP + (overlay_type -
450 																 TEXTURE_SCALED_TRANSPIXMAP);
451 		if (overlay_type < TEXTURE_TRANSPIXMAP
452 				|| overlay_type >= TEXTURE_TRANSPIXMAP_END)
453 			overlay_type = TEXTURE_TRANSPIXMAP_ALPHA;
454 
455 		if (transparency)
456 			transparency = (overlay_type != TEXTURE_TRANSPIXMAP_ALPHA);
457 	}
458 
459 	if (crop_x < 0) {
460 		root_x += crop_x;
461 		width = scale_width - crop_x;
462 		crop_x = 0;
463 		if (width < crop_width)
464 			width = crop_width;
465 	} else {
466 		width = crop_width + crop_x;
467 		if (width < scale_width)
468 			width = scale_width;
469 	}
470 
471 	if (crop_y < 0) {
472 		root_y += crop_y;
473 		height = scale_height - crop_y;
474 		crop_y = 0;
475 		if (height < crop_height)
476 			height = crop_height;
477 	} else {
478 		height = crop_height + crop_y;
479 		if (height < scale_height)
480 			height = scale_height;
481 	}
482 
483 	if (width < 1)
484 		width = 1;
485 	if (height < 1)
486 		height = 1;
487 
488 
489 	LOCAL_DEBUG_OUT
490 			("style \"%s\", texture_type = %d, im = %p, tint = 0x%lX, geom=(%dx%d%+d%+d), flip = %d",
491 			 style->name, style->texture_type, style->back_icon.image,
492 			 style->tint, width, height, root_x, root_y, flip);
493 
494 	if (transparency) {						/* in this case we need valid root image : */
495 
496 		if (ASDefaultScr->RootImage == NULL) {
497 			unsigned int root_w, root_h;
498 
499 			root_pixmap = ValidatePixmap (None, 1, 1, &root_w, &root_h);
500 			show_activity ("obtained Root pixmap = %lX, size %dx%d", root_pixmap,
501 										 root_w, root_h);
502 			ASDefaultScr->RootImage =
503 					clip_root_pixmap (root_pixmap, root_w, root_h);
504 
505 			if (ASDefaultScr->RootImage == NULL)
506 				ASDefaultScr->RootImage =
507 						grab_root_asimage (ASDefaultScr, None, False);
508 		}
509 		LOCAL_DEBUG_OUT ("RootImage = %p clip(%ux%u%+d%+d) size(%dx%d)",
510 										 ASDefaultScr->RootImage,
511 										 ASDefaultScr->RootClipArea.width,
512 										 ASDefaultScr->RootClipArea.height,
513 										 ASDefaultScr->RootClipArea.x,
514 										 ASDefaultScr->RootClipArea.y,
515 										 ASDefaultScr->RootImage ? ASDefaultScr->
516 										 RootImage->width : 0,
517 										 ASDefaultScr->RootImage ? ASDefaultScr->
518 										 RootImage->height : 0);
519 	}
520 	if (get_flags (flip, FLIP_VERTICAL)) {
521 		preflip_width = height;
522 		preflip_height = width;
523 	} else {
524 		preflip_width = width;
525 		preflip_height = height;
526 	}
527 
528 	switch (style->texture_type) {
529 	case TEXTURE_SOLID:
530 		im = create_asimage (width, height, 0);
531 		im->back_color = style->colors.back;
532 		break;
533 
534 	case TEXTURE_GRADIENT:
535 
536 	case TEXTURE_HGRADIENT:
537 	case TEXTURE_HCGRADIENT:
538 
539 	case TEXTURE_VGRADIENT:
540 	case TEXTURE_VCGRADIENT:
541 	case TEXTURE_GRADIENT_TL2BR:
542 	case TEXTURE_GRADIENT_BL2TR:
543 	case TEXTURE_GRADIENT_T2B:
544 	case TEXTURE_GRADIENT_L2R:
545 		{
546 			ASGradient *grad = flip_gradient (&(style->gradient), flip);
547 
548 			LOCAL_DEBUG_OUT
549 					("orig grad type = %d, translated grad_type = %d, texture_type = %d",
550 					 style->gradient.type, grad->type, style->texture_type);
551 			im = make_gradient (ASDefaultVisual, grad, width, height, 0xFFFFFFFF,
552 													ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
553 			if (grad != &(style->gradient))
554 				destroy_asgradient (&grad);
555 		}
556 		break;
557 	case TEXTURE_SHAPED_SCALED_PIXMAP:
558 	case TEXTURE_SCALED_PIXMAP:
559 		if (get_flags (style->set_flags, F_SLICE)) {
560 			im = slice_asimage2 (ASDefaultVisual, style->back_icon.image,
561 													 style->slice_x_start, style->slice_x_end,
562 													 style->slice_y_start, style->slice_y_end,
563 													 preflip_width, preflip_height, True,
564 													 ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
565 		} else
566 			im = scale_asimage (ASDefaultVisual, style->back_icon.image,
567 													preflip_width, preflip_height, ASA_ASImage, 0,
568 													ASIMAGE_QUALITY_DEFAULT);
569 		if (flip != 0)
570 			im = mystyle_flip_image (im, width, height, flip);
571 		break;
572 	case TEXTURE_SHAPED_PIXMAP:
573 	case TEXTURE_PIXMAP:
574 		if (get_flags (style->set_flags, F_SLICE)) {
575 			im = slice_asimage2 (ASDefaultVisual, style->back_icon.image,
576 													 style->slice_x_start, style->slice_x_end,
577 													 style->slice_y_start, style->slice_y_end,
578 													 preflip_width, preflip_height, False,
579 													 ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
580 		} else {
581 			im = tile_asimage (ASDefaultVisual, style->back_icon.image,
582 												 0, 0,
583 												 preflip_width, preflip_height, TINT_LEAVE_SAME,
584 												 ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
585 		}
586 		LOCAL_DEBUG_OUT ("back_icon.image = %p,im = %p, preflip_size=%dx%d",
587 										 style->back_icon.image, im, preflip_width,
588 										 preflip_height);
589 		if (flip != 0)
590 			im = mystyle_flip_image (im, width, height, flip);
591 		break;
592 	}
593 
594 	if (transparency) {
595 		if (ASDefaultScr->RootImage != NULL) {
596 			ASImage *root_im = ASDefaultScr->RootImage;
597 			int root_src_x = root_x - ASDefaultScr->RootClipArea.x;
598 			int root_src_y = root_y - ASDefaultScr->RootClipArea.y;
599 			Bool do_tint = (style->texture_type == TEXTURE_TRANSPARENT ||
600 											style->texture_type == TEXTURE_TRANSPARENT_TWOWAY);
601 			Bool do_blur = (get_flags (style->set_flags, F_BLUR)
602 											&& (style->blur_x > 1 || style->blur_y > 1));
603 
604 			LOCAL_DEBUG_OUT ("root+im = %p, blur is %s set, size = %dx%d",
605 											 root_im, get_flags (style->set_flags,
606 																					 F_BLUR) ? "is" : "not",
607 											 style->blur_x, style->blur_y);
608 			if (do_tint
609 					|| (do_blur
610 							&& (root_src_x != 0 || root_src_y != 0
611 									|| width != root_im->width
612 									|| height != root_im->height))) {
613 				ASImage *tmp = tile_asimage (ASDefaultVisual, root_im,
614 																		 root_src_x, root_src_y,
615 																		 width, height,
616 																		 do_tint ? style->tint :
617 																		 TINT_LEAVE_SAME,
618 																		 ASA_ASImage, 0,
619 																		 ASIMAGE_QUALITY_DEFAULT);
620 
621 				LOCAL_DEBUG_OUT ("tint result = %p", tmp);
622 				if (tmp) {
623 					root_src_x = root_src_y = 0;
624 					root_im = tmp;
625 				}
626 			}
627 			if (do_blur) {
628 #if 1
629 				ASImage *tmp =
630 						blur_asimage_gauss (ASDefaultVisual, root_im, style->blur_x,
631 																style->blur_y, 0xFFFFFFFF, ASA_ASImage,
632 																0, ASIMAGE_QUALITY_DEFAULT);
633 				LOCAL_DEBUG_OUT ("blur result = %p", tmp);
634 				if (tmp && tmp != root_im) {
635 					if (root_im != ASDefaultScr->RootImage)
636 						destroy_asimage (&root_im);
637 					root_im = tmp;
638 				}
639 #endif
640 			}
641 			if (do_tint)
642 				im = root_im;
643 			else {
644 				ASImageLayer layers[2];
645 				ASImage *scaled_im = NULL;
646 				Bool do_scale = False;
647 				int index = 1;					/* default is alphablending !!! */
648 
649 				init_image_layers (&layers[0], 2);
650 
651 				layers[0].im = root_im;
652 				if (style->texture_type == TEXTURE_SHAPED_SCALED_PIXMAP
653 						&& style->texture_type == TEXTURE_SHAPED_PIXMAP) {
654 					index = 1;						/* alphablending  */
655 				} else if (style->texture_type >= TEXTURE_SCALED_TRANSPIXMAP &&
656 									 style->texture_type < TEXTURE_SCALED_TRANSPIXMAP_END)
657 					index = style->texture_type - TEXTURE_SCALED_TRANSPIXMAP;
658 				else if (style->texture_type >= TEXTURE_TRANSPIXMAP
659 								 && style->texture_type < TEXTURE_TRANSPIXMAP_END)
660 					index = style->texture_type - TEXTURE_TRANSPIXMAP;
661 
662 				LOCAL_DEBUG_OUT ("index = %d", index);
663 				layers[0].merge_scanlines =
664 						mystyle_merge_scanlines_func_xref[index];
665 				layers[0].dst_x = 0;
666 				layers[0].dst_y = 0;
667 				layers[0].clip_x = root_src_x;
668 				layers[0].clip_y = root_src_y;
669 				layers[0].clip_width = width;
670 				layers[0].clip_height = height;
671 
672 				layers[1].im = im ? im : style->back_icon.image;
673 
674 				do_scale = (style->texture_type >= TEXTURE_SCALED_TRANSPIXMAP &&
675 										style->texture_type < TEXTURE_SCALED_TRANSPIXMAP_END);
676 
677 				if (get_flags (style->set_flags, F_SLICE)) {
678 					scaled_im = slice_asimage2 (ASDefaultVisual, layers[1].im,
679 																			style->slice_x_start,
680 																			style->slice_x_end,
681 																			style->slice_y_start,
682 																			style->slice_y_end, preflip_width,
683 																			preflip_height, do_scale,
684 																			ASA_ASImage, 0,
685 																			ASIMAGE_QUALITY_DEFAULT);
686 					LOCAL_DEBUG_OUT ("image scliced to %p", scaled_im);
687 				} else if (do_scale) {
688 					scaled_im = scale_asimage (ASDefaultVisual, layers[1].im,
689 																		 preflip_width, preflip_height,
690 																		 ASA_ASImage, 0,
691 																		 ASIMAGE_QUALITY_DEFAULT);
692 					LOCAL_DEBUG_OUT ("image scaled to %p", scaled_im);
693 				}
694 
695 				if (scaled_im) {
696 					/* here layers[1].im is always style->back_icon.image, so we should not destroy it ! */
697 					scaled_im = mystyle_flip_image (scaled_im, width, height, flip);
698 					layers[1].im = scaled_im;
699 					LOCAL_DEBUG_OUT ("image flipped to %p", layers[1].im);
700 					/* scaled_im got destroyed in mystyle_flip_image if it had to be */
701 				} else if (flip != 0 && layers[1].im == style->back_icon.image) {
702 					/* safely assuming that im is NULL at this point,( see logic above ) */
703 					layers[1].im = im = flip_asimage (ASDefaultVisual, layers[1].im,
704 																						0, 0,
705 																						width, height, flip,
706 																						ASA_ASImage, 100,
707 																						ASIMAGE_QUALITY_DEFAULT);
708 				}
709 				layers[1].merge_scanlines = layers[0].merge_scanlines;
710 				layers[1].dst_x = 0;
711 				layers[1].dst_y = 0;
712 				layers[1].clip_x = 0;
713 				layers[1].clip_y = 0;
714 				layers[1].clip_width = width;
715 				layers[1].clip_height = height;
716 
717 				{
718 					ASImage *tmp = merge_layers (ASDefaultVisual, &layers[0], 2,
719 																			 width, height,
720 																			 ASA_ASImage, 0,
721 																			 ASIMAGE_QUALITY_DEFAULT);
722 
723 					if (tmp) {
724 						if (im) {
725 							if (style->texture_type == TEXTURE_SHAPED_SCALED_PIXMAP ||
726 									style->texture_type == TEXTURE_SHAPED_PIXMAP) {
727 								/*we need to keep alpha channel intact */
728 								LOCAL_DEBUG_OUT ("copying alpha channel from %p to %p", im,
729 																 tmp);
730 								copy_asimage_channel (tmp, IC_ALPHA, im, IC_ALPHA);
731 							}
732 							if (im != ASDefaultScr->RootImage)
733 								safe_asimage_destroy (im);
734 						}
735 						im = tmp;
736 					}
737 				}
738 				if (scaled_im)
739 					destroy_asimage (&scaled_im);
740 			}
741 			if (root_im && root_im != ASDefaultScr->RootImage && root_im != im)
742 				destroy_asimage (&root_im);
743 		} else
744 			show_warning
745 					("MyStyle \"%s\" : failed to accure Root background image",
746 					 style->name);
747 	}
748 	/* simply creating solid color image under no circumstances we want to return NULL here */
749 	if (im == NULL) {
750 		im = create_asimage (width, height, 100);
751 		im->back_color = style->colors.back;
752 		show_warning
753 				("MyStyle \"%s\" : failed to generate background image - using solid fill instead with color #0x%8.8X",
754 				 style->name, style->colors.back);
755 	}
756 
757 	if (underlayment) {
758 		ASImageLayer layers[2];
759 		int index = 1;							/* default is alphablending !!! */
760 
761 		init_image_layers (&layers[0], 2);
762 
763 		layers[0].im = underlayment;
764 		index = overlay_type - TEXTURE_TRANSPIXMAP;
765 
766 		LOCAL_DEBUG_OUT ("index = %d", index);
767 		layers[0].merge_scanlines = mystyle_merge_scanlines_func_xref[index];
768 		layers[0].dst_x = 0;
769 		layers[0].dst_y = 0;
770 		layers[0].clip_x = 0;
771 		layers[0].clip_y = 0;
772 		layers[0].clip_width = width;
773 		layers[0].clip_height = height;
774 
775 		layers[1].im = im;
776 		layers[1].merge_scanlines = layers[0].merge_scanlines;
777 		layers[1].dst_x = 0;
778 		layers[1].dst_y = 0;
779 		layers[1].clip_x = 0;
780 		layers[1].clip_y = 0;
781 		layers[1].clip_width = width;
782 		layers[1].clip_height = height;
783 
784 		{
785 			ASImage *tmp = merge_layers (ASDefaultVisual, &layers[0], 2,
786 																	 width, height,
787 																	 ASA_ASImage, 0,
788 																	 ASIMAGE_QUALITY_DEFAULT);
789 
790 			if (tmp) {
791 				if (im) {
792 					if (style->texture_type == TEXTURE_SHAPED_SCALED_PIXMAP ||
793 							style->texture_type == TEXTURE_SHAPED_PIXMAP) {
794 						/*we need to keep alpha channel intact */
795 						LOCAL_DEBUG_OUT ("copying alpha channel from %p to %p", im,
796 														 tmp);
797 						copy_asimage_channel (tmp, IC_ALPHA, im, IC_ALPHA);
798 					}
799 					if (im != ASDefaultScr->RootImage)
800 						safe_asimage_destroy (im);
801 				}
802 				im = tmp;
803 			}
804 		}
805 	}
806 
807 	if (style->overlay) {
808 		ASImage *overlayed =
809 				mystyle_make_image_int (style->overlay, root_x, root_y, crop_x,
810 																crop_y, crop_width, crop_height,
811 																scale_width, scale_height, flip, im,
812 																style->overlay_type);
813 /* 		fprintf( stderr, "overlay_style = %p\n", style->overlay ); */
814 		if (overlayed) {
815 			if (im && overlayed != im && im != ASDefaultScr->RootImage)
816 				safe_asimage_destroy (im);
817 			im = overlayed;
818 		}
819 	}
820 	if (crop_x > 0 || crop_y > 0 ||
821 			(crop_width > 0 && crop_width < im->width) || (crop_height > 0
822 																										 && crop_height <
823 																										 im->height)) {
824 		ASImage *cropped_im = tile_asimage (ASDefaultVisual, im,
825 																				crop_x, crop_y,
826 																				crop_width, crop_height,
827 																				TINT_LEAVE_SAME,
828 																				ASA_ASImage, 0,
829 																				ASIMAGE_QUALITY_DEFAULT);
830 
831 		if (cropped_im) {
832 			if (im && cropped_im != im && im != ASDefaultScr->RootImage)
833 				safe_asimage_destroy (im);
834 			im = cropped_im;
835 		}
836 	}
837 	return im;
838 }
839 
mystyle_make_image(MyStyle * style,int root_x,int root_y,int width,int height,int flip)840 ASImage *mystyle_make_image (MyStyle * style, int root_x, int root_y,
841 														 int width, int height, int flip)
842 {
843 	if (style != NULL)
844 		return mystyle_make_image_int (style, root_x, root_y, 0, 0, width,
845 																	 height, width, height, flip, NULL, 0);
846 	return NULL;
847 }
848 
mystyle_crop_image(MyStyle * style,int root_x,int root_y,int crop_x,int crop_y,int width,int height,int scale_width,int scale_height,int flip)849 ASImage *mystyle_crop_image (MyStyle * style, int root_x, int root_y,
850 														 int crop_x, int crop_y, int width, int height,
851 														 int scale_width, int scale_height, int flip)
852 {
853 	if (style != NULL)
854 		return mystyle_make_image_int (style, root_x, root_y, crop_x, crop_y,
855 																	 width, height, scale_width,
856 																	 scale_height, flip, NULL, 0);
857 	return NULL;
858 }
859 
860 
861 /*************************************************************************/
862 /* Mystyle creation/deletion                                             */
863 /*************************************************************************/
mystyle_free_resources(MyStyle * style)864 static void mystyle_free_resources (MyStyle * style)
865 {
866 	if (style->magic == MAGIC_MYSTYLE) {
867 		LOCAL_DEBUG_OUT
868 				("style %p, style->name = \"%s\", style->font->name = \"%s\"",
869 				 style, style->name ? style->name : "(null)",
870 				 style->font.name ? style->font.name : "(null)");
871 
872 		if (get_flags (style->user_flags, F_FONT)) {
873 			unload_font (&style->font);
874 		}
875 		if (style->user_flags & F_BACKGRADIENT) {
876 			free (style->gradient.color);
877 			free (style->gradient.offset);
878 		}
879 		if (!get_flags (style->inherit_flags, F_BACKTRANSPIXMAP)) {
880 			LOCAL_DEBUG_OUT ("calling mystyle_free_back_icon for style %p",
881 											 style);
882 			mystyle_free_back_icon (style);
883 		}
884 	}
885 }
886 
mystyle_init(MyStyle * style)887 void mystyle_init (MyStyle * style)
888 {
889 	style->user_flags = 0;
890 	style->inherit_flags = 0;
891 	style->set_flags = 0;
892 	style->flags = 0;
893 	style->name = NULL;
894 	style->text_style = 0;
895 	style->font.name = NULL;
896 	style->font.as_font = NULL;
897 	style->colors.fore = ARGB32_White;
898 	style->colors.back = ARGB32_Black;
899 	style->relief.fore = style->colors.back;
900 	style->relief.back = style->colors.fore;
901 	style->texture_type = 0;
902 	style->gradient.npoints = 0;
903 	style->gradient.color = NULL;
904 	style->gradient.offset = NULL;
905 	style->back_icon.pix = None;
906 	style->back_icon.mask = None;
907 	style->back_icon.alpha = None;
908 	style->tint = TINT_LEAVE_SAME;
909 	style->back_icon.image = NULL;
910 }
911 
912 
mystyle_destroy(ASHashableValue value,void * data)913 void mystyle_destroy (ASHashableValue value, void *data)
914 {
915 	if ((char *)value != NULL) {
916 /*	fprintf( stderr, "destroying mystyle [%s]\n", value.string_val ); */
917 		free ((char *)value);				/* destroying our name */
918 	}
919 	if (data != NULL) {
920 		MyStyle *style = (MyStyle *) data;
921 
922 		mystyle_free_resources (style);
923 		style->magic = 0;						/* invalidating memory block */
924 		free (data);
925 	}
926 }
927 
mystyle_list_init()928 ASHashTable *mystyle_list_init ()
929 {
930 	ASHashTable *list = NULL;
931 
932 	list =
933 			create_ashash (0, casestring_hash_value, casestring_compare,
934 										 mystyle_destroy);
935 
936 	return list;
937 }
938 
mystyle_list_new(struct ASHashTable * list,char * name)939 MyStyle *mystyle_list_new (struct ASHashTable * list, char *name)
940 {
941 	MyStyle *style = NULL;
942 	ASHashData hdata = { 0 };
943 
944 	if (name == NULL)
945 		return NULL;
946 
947 	if (list == NULL) {
948 		if (ASDefaultScr->Look.styles_list == NULL)
949 			if ((ASDefaultScr->Look.styles_list = mystyle_list_init ()) == NULL)
950 				return NULL;
951 		list = ASDefaultScr->Look.styles_list;
952 	}
953 
954 	if (get_hash_item (list, AS_HASHABLE (name), &hdata.vptr) == ASH_Success) {
955 		if ((style = hdata.vptr) != NULL) {
956 			if (style->magic == MAGIC_MYSTYLE)
957 				return style;
958 			else
959 				remove_hash_item (list, (ASHashableValue) name, NULL, True);
960 		}
961 	}
962 	style = (MyStyle *) safecalloc (1, sizeof (MyStyle));
963 
964 	mystyle_init (style);
965 	style->name = mystrdup (name);
966 
967 	if (add_hash_item (list, AS_HASHABLE (style->name), style) != ASH_Success) {	/* something terrible has happen */
968 		if (style->name)
969 			free (style->name);
970 		free (style);
971 		return NULL;
972 	}
973 	style->magic = MAGIC_MYSTYLE;
974 	return style;
975 }
976 
mystyle_new_with_name(char * name)977 MyStyle *mystyle_new_with_name (char *name)
978 {
979 	if (name == NULL)
980 		return NULL;
981 	return mystyle_list_new (NULL, name);
982 }
983 
984 
985 /* destruction of all mystyle records : */
mystyle_list_destroy_all(ASHashTable ** plist)986 void mystyle_list_destroy_all (ASHashTable ** plist)
987 {
988 	if (plist == NULL)
989 		plist = &(ASDefaultScr->Look.styles_list);
990 	destroy_ashash (plist);
991 }
992 
mystyle_destroy_all()993 void mystyle_destroy_all ()
994 {
995 	mystyle_list_destroy_all (NULL);
996 }
997 
998 
999 /*
1000  * MyStyle Lookup functions :
1001  */
mystyle_list_find(struct ASHashTable * list,const char * name)1002 MyStyle *mystyle_list_find (struct ASHashTable *list, const char *name)
1003 {
1004 	ASHashData hdata = { 0 };
1005 	if (list == NULL)
1006 		list = ASDefaultScr->Look.styles_list;
1007 
1008 	if (list && name)
1009 		if (get_hash_item (list, AS_HASHABLE ((char *)name), &hdata.vptr) !=
1010 				ASH_Success)
1011 			hdata.vptr = NULL;
1012 	return hdata.vptr;
1013 }
1014 
mystyle_list_find_or_default(struct ASHashTable * list,const char * name)1015 MyStyle *mystyle_list_find_or_default (struct ASHashTable * list,
1016 																			 const char *name)
1017 {
1018 	ASHashData hdata = { 0 };
1019 
1020 	if (list == NULL)
1021 		list = ASDefaultScr->Look.styles_list;
1022 
1023 	if (name == NULL)
1024 		name = DefaultMyStyleName;
1025 	if (list && name)
1026 		if (get_hash_item (list, AS_HASHABLE ((char *)name), &hdata.vptr) !=
1027 				ASH_Success)
1028 			if (get_hash_item
1029 					(list, AS_HASHABLE (DefaultMyStyleName),
1030 					 &hdata.vptr) != ASH_Success)
1031 				hdata.vptr = NULL;
1032 	return hdata.vptr;
1033 }
1034 
1035 /* find a style by name */
mystyle_find(const char * name)1036 MyStyle *mystyle_find (const char *name)
1037 {
1038 	return mystyle_list_find (NULL, name);
1039 }
1040 
1041 /* find a style by name or return the default style */
mystyle_find_or_default(const char * name)1042 MyStyle *mystyle_find_or_default (const char *name)
1043 {
1044 	return mystyle_list_find_or_default (NULL, name);
1045 }
1046 
1047 /*
1048  * merges two styles, with the result in child
1049  * if override == False, will not override fields already set
1050  * if copy == True, copies instead of inheriting; this is important, because
1051  *   inherited members are deleted when their real parent is deleted; don't
1052  *   inherit if the parent style could go away before the child
1053  */
mystyle_merge_font(MyStyle * style,MyFont * font,Bool override)1054 void mystyle_merge_font (MyStyle * style, MyFont * font, Bool override)
1055 {
1056 	if (override && get_flags (style->user_flags, F_FONT)) {
1057 		unload_font (&style->font);
1058 		clear_flags (style->user_flags, F_FONT);
1059 		clear_flags (style->set_flags, F_FONT);
1060 	}
1061 	if (override || !get_flags (style->set_flags, F_FONT)) {
1062 		set_string (&(style->font.name), mystrdup (font->name));
1063 		style->font.as_font = dup_asfont (font->as_font);
1064 		set_flags (style->user_flags, F_FONT);
1065 		clear_flags (style->inherit_flags, F_FONT);
1066 	}
1067 }
1068 
1069 void
mystyle_merge_styles(MyStyle * parent,MyStyle * child,Bool override,Bool copy)1070 mystyle_merge_styles (MyStyle * parent, MyStyle * child, Bool override,
1071 											Bool copy)
1072 {
1073 	if (parent == NULL || child == NULL)
1074 		return;
1075 	if (parent->set_flags & F_FONT)
1076 		mystyle_merge_font (child, &(parent->font), override);
1077 
1078 	if (parent->set_flags & F_TEXTSTYLE) {
1079 		if ((override == True) || !(child->set_flags & F_TEXTSTYLE)) {
1080 			child->text_style = parent->text_style;
1081 
1082 			if (copy == False) {
1083 				child->user_flags &= ~F_TEXTSTYLE;
1084 				child->inherit_flags |= F_TEXTSTYLE;
1085 			} else {
1086 				child->user_flags |= F_TEXTSTYLE;
1087 				child->inherit_flags &= ~F_TEXTSTYLE;
1088 			}
1089 		}
1090 	}
1091 	if (parent->set_flags & F_FORECOLOR) {
1092 		if ((override == True) || !(child->set_flags & F_FORECOLOR)) {
1093 			if (override == True)
1094 				child->texture_type = parent->texture_type;
1095 			child->colors.fore = parent->colors.fore;
1096 			if (copy == False) {
1097 				child->user_flags &= ~F_FORECOLOR;
1098 				child->inherit_flags |= F_FORECOLOR;
1099 			} else {
1100 				child->user_flags |= F_FORECOLOR;
1101 				child->inherit_flags &= ~F_FORECOLOR;
1102 			}
1103 		}
1104 	}
1105 	if (parent->set_flags & F_BACKCOLOR) {
1106 		if ((override == True) || !(child->set_flags & F_BACKCOLOR)) {
1107 			child->colors.back = parent->colors.back;
1108 			child->relief = parent->relief;
1109 			if (copy == False) {
1110 				child->user_flags &= ~F_BACKCOLOR;
1111 				child->inherit_flags |= F_BACKCOLOR;
1112 			} else {
1113 				child->user_flags |= F_BACKCOLOR;
1114 				child->inherit_flags &= ~F_BACKCOLOR;
1115 			}
1116 		}
1117 	}
1118 	if (parent->set_flags & F_SLICE) {
1119 		if ((override == True) || !(child->set_flags & F_SLICE)) {
1120 			child->slice_x_start = parent->slice_x_start;
1121 			child->slice_x_end = parent->slice_x_end;
1122 			child->slice_y_start = parent->slice_y_start;
1123 			child->slice_y_end = parent->slice_y_end;
1124 			if (copy == False) {
1125 				child->user_flags &= ~F_SLICE;
1126 				child->inherit_flags |= F_SLICE;
1127 			} else {
1128 				child->user_flags |= F_SLICE;
1129 				child->inherit_flags &= ~F_SLICE;
1130 			}
1131 		}
1132 	}
1133 	if (parent->set_flags & F_BACKGRADIENT) {
1134 		if ((override == True) || !(child->set_flags & F_BACKGRADIENT)) {
1135 			if (override == True)
1136 				child->texture_type = parent->texture_type;
1137 			child->gradient = parent->gradient;
1138 			if (copy == False) {
1139 				child->user_flags &= ~F_BACKGRADIENT;
1140 				child->inherit_flags |= F_BACKGRADIENT;
1141 			} else {
1142 				child->user_flags |= F_BACKGRADIENT;
1143 				child->inherit_flags &= ~F_BACKGRADIENT;
1144 			}
1145 		}
1146 	}
1147 	if (parent->set_flags & F_BACKPIXMAP) {
1148 		if ((override == True) && (child->user_flags & F_BACKPIXMAP)) {
1149 			LOCAL_DEBUG_OUT ("calling mystyle_free_back_icon for style %p",
1150 											 child);
1151 			mystyle_free_back_icon (child);
1152 		}
1153 		if ((override == True) || !(child->set_flags & F_BACKPIXMAP)) {
1154 			if (override == True)
1155 				child->texture_type = parent->texture_type;
1156 			if ((parent->texture_type == TEXTURE_TRANSPARENT ||
1157 					 parent->texture_type == TEXTURE_TRANSPARENT_TWOWAY) &&
1158 					(override == True ||
1159 					 (child->texture_type != TEXTURE_TRANSPARENT
1160 						&& child->texture_type != TEXTURE_TRANSPARENT_TWOWAY))) {
1161 				child->tint = parent->tint;
1162 			}
1163 			if (!copy) {
1164 				child->back_icon = parent->back_icon;
1165 				clear_flags (child->user_flags, F_BACKPIXMAP | F_BACKTRANSPIXMAP);
1166 				set_flags (child->inherit_flags, F_BACKPIXMAP);
1167 				if (get_flags (parent->set_flags, F_BACKTRANSPIXMAP))
1168 					set_flags (child->inherit_flags, F_BACKTRANSPIXMAP);
1169 			} else {
1170 				GC gc = create_visual_gc (ASDefaultVisual, ASDefaultRoot, 0, NULL);
1171 
1172 				child->back_icon.pix =
1173 						XCreatePixmap (dpy, ASDefaultRoot, parent->back_icon.width,
1174 													 parent->back_icon.height,
1175 													 ASDefaultVisual->visual_info.depth);
1176 				XCopyArea (dpy, parent->back_icon.pix, child->back_icon.pix, gc, 0,
1177 									 0, parent->back_icon.width, parent->back_icon.height, 0,
1178 									 0);
1179 				if (parent->back_icon.mask != None) {
1180 					GC mgc = XCreateGC (dpy, parent->back_icon.mask, 0, NULL);
1181 
1182 					child->back_icon.mask =
1183 							XCreatePixmap (dpy, ASDefaultRoot, parent->back_icon.width,
1184 														 parent->back_icon.height, 1);
1185 					XCopyArea (dpy, parent->back_icon.mask, child->back_icon.mask,
1186 										 mgc, 0, 0, parent->back_icon.width,
1187 										 parent->back_icon.height, 0, 0);
1188 					XFreeGC (dpy, mgc);
1189 				}
1190 				if (parent->back_icon.alpha != None) {
1191 					GC mgc = XCreateGC (dpy, parent->back_icon.alpha, 0, NULL);
1192 
1193 					child->back_icon.alpha =
1194 							XCreatePixmap (dpy, ASDefaultRoot, parent->back_icon.width,
1195 														 parent->back_icon.height, 8);
1196 					XCopyArea (dpy, parent->back_icon.alpha, child->back_icon.alpha,
1197 										 mgc, 0, 0, parent->back_icon.width,
1198 										 parent->back_icon.height, 0, 0);
1199 					XFreeGC (dpy, mgc);
1200 				}
1201 				if (parent->back_icon.image)
1202 					child->back_icon.image = dup_asimage (parent->back_icon.image);
1203 				else
1204 					child->back_icon.image = 0;
1205 				child->back_icon.width = parent->back_icon.width;
1206 				child->back_icon.height = parent->back_icon.height;
1207 				child->user_flags |=
1208 						F_BACKPIXMAP | (parent->set_flags & F_BACKTRANSPIXMAP);
1209 				child->inherit_flags &= ~(F_BACKPIXMAP | F_BACKTRANSPIXMAP);
1210 				XFreeGC (dpy, gc);
1211 			}
1212 		}
1213 	}
1214 	if (parent->set_flags & F_DRAWTEXTBACKGROUND) {
1215 		if ((override == True) || !(child->set_flags & F_DRAWTEXTBACKGROUND)) {
1216 			child->flags &= ~F_DRAWTEXTBACKGROUND;
1217 			child->flags |= parent->flags & F_DRAWTEXTBACKGROUND;
1218 			if (copy == False) {
1219 				child->user_flags &= ~F_DRAWTEXTBACKGROUND;
1220 				child->inherit_flags |= F_DRAWTEXTBACKGROUND;
1221 			} else {
1222 				child->user_flags |= F_DRAWTEXTBACKGROUND;
1223 				child->inherit_flags &= ~F_DRAWTEXTBACKGROUND;
1224 			}
1225 		}
1226 	}
1227 	if (parent->set_flags & F_OVERLAY) {
1228 		if ((override == True) || !(child->set_flags & F_OVERLAY)) {
1229 			child->flags &= ~F_OVERLAY;
1230 			child->flags |= parent->flags & F_OVERLAY;
1231 			child->overlay = parent->overlay;
1232 			child->overlay_type = parent->overlay_type;
1233 			if (copy == False) {
1234 				child->user_flags &= ~F_OVERLAY;
1235 				child->inherit_flags |= F_OVERLAY;
1236 			} else {
1237 				child->user_flags |= F_OVERLAY;
1238 				child->inherit_flags &= ~F_OVERLAY;
1239 			}
1240 		}
1241 	}
1242 	child->set_flags = child->user_flags | child->inherit_flags;
1243 }
1244 
1245 /*
1246  * convert an old two-color gradient to a multi-point gradient
1247  */
1248 int
mystyle_parse_old_gradient(int type,ARGB32 c1,ARGB32 c2,ASGradient * gradient)1249 mystyle_parse_old_gradient (int type, ARGB32 c1, ARGB32 c2,
1250 														ASGradient * gradient)
1251 {
1252 	int cylindrical = 0;
1253 
1254 	switch (type) {
1255 	case TEXTURE_GRADIENT:
1256 		type = TEXTURE_GRADIENT_TL2BR;
1257 		break;
1258 	case TEXTURE_HGRADIENT:
1259 		type = TEXTURE_GRADIENT_T2B;
1260 		break;
1261 	case TEXTURE_HCGRADIENT:
1262 		type = TEXTURE_GRADIENT_T2B;
1263 		cylindrical = 1;
1264 		break;
1265 	case TEXTURE_VGRADIENT:
1266 		type = TEXTURE_GRADIENT_L2R;
1267 		break;
1268 	case TEXTURE_VCGRADIENT:
1269 		type = TEXTURE_GRADIENT_L2R;
1270 		cylindrical = 1;
1271 		break;
1272 	default:
1273 		break;
1274 	}
1275 	if (gradient) {
1276 		gradient->npoints = 2 + cylindrical;
1277 		gradient->color = NEW_ARRAY (ARGB32, gradient->npoints);
1278 		gradient->offset = NEW_ARRAY (double, gradient->npoints);
1279 
1280 		gradient->color[0] = c1;
1281 		gradient->color[1] = c2;
1282 		if (cylindrical)
1283 			gradient->color[2] = c1;
1284 		gradient->offset[0] = 0.0;
1285 		if (cylindrical)
1286 			gradient->offset[1] = 0.5;
1287 		gradient->offset[gradient->npoints - 1] = 1.0;
1288 		gradient->type = mystyle_translate_grad_type (type);
1289 	}
1290 	return type;
1291 }
1292 
1293 void
mystyle_merge_colors(MyStyle * style,int type,char * fore,char * back,char * gradient,char * pixmap)1294 mystyle_merge_colors (MyStyle * style, int type, char *fore, char *back,
1295 											char *gradient, char *pixmap)
1296 {
1297 	if (style == NULL)
1298 		return;
1299 	if ((fore != NULL) && !((*style).user_flags & F_FORECOLOR)) {
1300 		if (parse_argb_color (fore, &((*style).colors.fore)) != fore)
1301 			(*style).user_flags |= F_FORECOLOR;
1302 	}
1303 	if ((back != NULL) && !((*style).user_flags & F_BACKCOLOR)) {
1304 		if (parse_argb_color (back, &((*style).colors.back)) != back) {
1305 			(*style).relief.fore = GetHilite ((*style).colors.back);
1306 			(*style).relief.back = GetShadow ((*style).colors.back);
1307 			(*style).user_flags |= F_BACKCOLOR;
1308 		}
1309 	}
1310 	if (type >= 0) {
1311 		switch (type) {
1312 		case TEXTURE_GRADIENT:
1313 			style->texture_type = TEXTURE_GRADIENT_TL2BR;
1314 			break;
1315 		case TEXTURE_HGRADIENT:
1316 			style->texture_type = TEXTURE_GRADIENT_L2R;
1317 			break;
1318 		case TEXTURE_HCGRADIENT:
1319 			style->texture_type = TEXTURE_GRADIENT_L2R;
1320 			break;
1321 		case TEXTURE_VGRADIENT:
1322 			style->texture_type = TEXTURE_GRADIENT_T2B;
1323 			break;
1324 		case TEXTURE_VCGRADIENT:
1325 			style->texture_type = TEXTURE_GRADIENT_T2B;
1326 			break;
1327 		default:
1328 			style->texture_type = type;
1329 			break;
1330 		}
1331 	}
1332 	if ((type > 0) && (type < TEXTURE_PIXMAP)
1333 			&& !((*style).user_flags & F_BACKGRADIENT)) {
1334 		if (gradient != NULL) {
1335 			ARGB32 c1, c2 = 0;
1336 			ASGradient grad;
1337 			char *ptr;
1338 
1339 			ptr = (char *)parse_argb_color (gradient, &c1);
1340 			parse_argb_color (ptr, &c2);
1341 			if (ptr != gradient
1342 					&& (type =
1343 							mystyle_parse_old_gradient (type, c1, c2, &grad)) >= 0) {
1344 				if (style->user_flags & F_BACKGRADIENT) {
1345 					free (style->gradient.color);
1346 					free (style->gradient.offset);
1347 				}
1348 				style->gradient = grad;
1349 				grad.type = mystyle_translate_grad_type (type);
1350 				style->texture_type = type;
1351 				style->user_flags |= F_BACKGRADIENT;
1352 			} else
1353 				show_error ("bad gradient definition in look file: %s", gradient);
1354 		}
1355 	} else if ((type == TEXTURE_PIXMAP)
1356 						 && !get_flags (style->user_flags, F_BACKPIXMAP)) {
1357 		if (pixmap != NULL) {
1358 /* treat second parameter as an image filename : */
1359 			if (load_icon
1360 					(&(style->back_icon), pixmap, ASDefaultScr->image_manager)) {
1361 				style->texture_type = type;
1362 				set_flags (style->user_flags, F_BACKPIXMAP);
1363 			} else
1364 				show_error ("failed to load image file \"%s\" in MyStyle \"%s\".",
1365 										pixmap, style->name);
1366 		}
1367 	}
1368 	(*style).set_flags = (*style).user_flags | (*style).inherit_flags;
1369 }
1370 
mystyle_inherit_font(MyStyle * style,MyFont * font)1371 void mystyle_inherit_font (MyStyle * style, MyFont * font)
1372 {
1373 	/* NOTE: these should have inherit_flags set, so the font is only
1374 	 *       unloaded once */
1375 	if (style != NULL && !(style->set_flags & F_FONT)) {
1376 		set_string (&(style->font.name), mystrdup (font->name));
1377 		style->font.as_font = dup_asfont (font->as_font);
1378 		clear_flags (style->inherit_flags, F_FONT);
1379 		set_flags (style->user_flags, F_FONT);	/* to prevent confusion */
1380 		style->set_flags = style->user_flags | style->inherit_flags;
1381 	}
1382 }
1383 
1384 
mystyle_make_bevel(MyStyle * style,ASImageBevel * bevel,int hilite,Bool reverse)1385 ASImageBevel *mystyle_make_bevel (MyStyle * style, ASImageBevel * bevel,
1386 																	int hilite, Bool reverse)
1387 {
1388 	if (style && (hilite & HILITE_MASK) != 0 &&
1389 			(hilite & (NO_HILITE_INLINE | NO_HILITE_OUTLINE)) !=
1390 			(NO_HILITE_INLINE | NO_HILITE_OUTLINE)) {
1391 		int extra_hilite = get_flags (hilite, EXTRA_HILITE) ? 2 : 0;
1392 
1393 		if (bevel == NULL)
1394 			bevel = safecalloc (1, sizeof (ASImageBevel));
1395 		else
1396 			memset (bevel, 0x00, sizeof (ASImageBevel));
1397 		if (reverse != 0) {
1398 			bevel->lo_color = style->relief.fore;
1399 			bevel->lolo_color = GetHilite (style->relief.fore);
1400 			bevel->hi_color = style->relief.back;
1401 			bevel->hihi_color = GetShadow (style->relief.back);
1402 		} else {
1403 			bevel->hi_color = style->relief.fore;
1404 			bevel->hihi_color = GetHilite (style->relief.fore);
1405 			bevel->lo_color = style->relief.back;
1406 			bevel->lolo_color = GetShadow (style->relief.back);
1407 		}
1408 		bevel->hilo_color = GetAverage (bevel->hi_color, bevel->lo_color);
1409 #if 1
1410 		if (!get_flags (hilite, NO_HILITE_OUTLINE)) {
1411 			if (get_flags (hilite, NORMAL_HILITE)) {
1412 				bevel->left_outline = bevel->top_outline = bevel->right_outline =
1413 						bevel->bottom_outline = 1;
1414 				bevel->left_inline = bevel->top_inline = bevel->right_inline =
1415 						bevel->bottom_inline =
1416 						extra_hilite + get_flags (hilite, NO_HILITE_INLINE) ? 0 : 1;
1417 			} else {
1418 #ifndef DONT_HILITE_PLAIN
1419 				bevel->left_inline = bevel->top_inline = bevel->right_inline =
1420 						bevel->bottom_inline = extra_hilite;
1421 #endif
1422 			}
1423 		}
1424 #endif
1425 		if (get_flags (hilite, LEFT_HILITE)) {
1426 			bevel->left_outline++;
1427 			if (!get_flags (hilite, NO_HILITE_INLINE))
1428 				bevel->left_inline++;
1429 			if (get_flags (hilite, NO_HILITE_OUTLINE)) {
1430 				bevel->left_outline++;
1431 				bevel->left_inline += extra_hilite;
1432 			}
1433 		}
1434 		if (get_flags (hilite, TOP_HILITE)) {
1435 			bevel->top_outline++;
1436 			if (!get_flags (hilite, NO_HILITE_INLINE))
1437 				bevel->top_inline++;
1438 			if (get_flags (hilite, NO_HILITE_OUTLINE))
1439 				bevel->top_inline += extra_hilite;
1440 		}
1441 		if (get_flags (hilite, RIGHT_HILITE)) {
1442 			bevel->right_outline++;
1443 			if (!get_flags (hilite, NO_HILITE_INLINE))
1444 				bevel->right_inline++;
1445 			if (get_flags (hilite, NO_HILITE_OUTLINE))
1446 				bevel->right_inline += extra_hilite;
1447 		}
1448 		if (get_flags (hilite, BOTTOM_HILITE)) {
1449 			bevel->bottom_outline++;
1450 			if (!get_flags (hilite, NO_HILITE_INLINE))
1451 				bevel->bottom_inline++;
1452 			if (get_flags (hilite, NO_HILITE_OUTLINE))
1453 				bevel->bottom_inline += extra_hilite;
1454 		}
1455 /* experimental code */
1456 #if 1
1457 		if (!get_flags (hilite, NO_HILITE_INLINE)) {
1458 			if (bevel->top_outline > 1) {
1459 				bevel->top_inline += bevel->top_outline - 1;
1460 				bevel->top_outline = 1;
1461 			}
1462 			if (bevel->left_outline > 1) {
1463 				bevel->left_inline += bevel->left_outline - 1;
1464 				bevel->left_outline = 1;
1465 			}
1466 			if (bevel->right_outline > 1) {
1467 				bevel->right_inline += bevel->right_outline - 1;
1468 				bevel->right_outline = 1;
1469 			}
1470 			if (bevel->bottom_outline > 1) {
1471 				bevel->bottom_inline += bevel->bottom_outline - 1;
1472 				bevel->bottom_outline = 1;
1473 			}
1474 		}
1475 #endif
1476 	} else if (bevel)
1477 		memset (bevel, 0x00, sizeof (ASImageBevel));
1478 
1479 	return bevel;
1480 }
1481 
mystyle_draw_text_image(MyStyle * style,const char * text,unsigned long encoding)1482 ASImage *mystyle_draw_text_image (MyStyle * style, const char *text,
1483 																	unsigned long encoding)
1484 {
1485 	ASImage *im = NULL;
1486 
1487 	if (style && text) {
1488 		/* load fonts on demand only - no need to waste memory if ain't never gonna use it ! */
1489 		if (style->font.as_font == NULL)
1490 			load_font (NULL, &style->font);
1491 
1492 		if (style->font.as_font) {
1493 			ASTextAttributes attr =
1494 					{ ASTA_VERSION_1, ASTA_UseTabStops, AST_Plain, ASCT_Char, 8, 0,
1495 				NULL, 0, ARGB32_White
1496 			};
1497 
1498 			attr.type = style->text_style;
1499 			attr.fore_color = style->colors.fore;
1500 
1501 			switch (encoding) {
1502 			case AS_Text_ASCII:
1503 				attr.char_type = ASCT_Char;
1504 				break;
1505 			case AS_Text_UTF8:
1506 				attr.char_type = ASCT_UTF8;
1507 				break;
1508 			case AS_Text_UNICODE:
1509 				attr.char_type = ASCT_Unicode;
1510 				break;
1511 			}
1512 
1513 			im = draw_fancy_text (text, style->font.as_font, &attr, 100, 0);
1514 
1515 			LOCAL_DEBUG_OUT ("encoding is %ld, im is %p, back_color is %lX",
1516 											 encoding, im, style->colors.fore);
1517 			if (im) {
1518 				im->back_color = style->colors.fore;
1519 			}
1520 		}
1521 	}
1522 	return im;
1523 }
1524 
mystyle_get_font_height(MyStyle * style)1525 unsigned int mystyle_get_font_height (MyStyle * style)
1526 {
1527 	if (style) {
1528 		if (style->font.as_font == NULL)
1529 			load_font (NULL, &style->font);
1530 
1531 		if (style->font.as_font)
1532 			return style->font.as_font->max_height;
1533 	}
1534 	return 1;
1535 }
1536 
1537 void
mystyle_get_text_size(MyStyle * style,const char * text,unsigned int * width,unsigned int * height)1538 mystyle_get_text_size (MyStyle * style, const char *text,
1539 											 unsigned int *width, unsigned int *height)
1540 {
1541 	if (style && text) {
1542 		if (style->font.as_font == NULL)
1543 			load_font (NULL, &style->font);
1544 
1545 		if (style->font.as_font)
1546 			get_text_size (text, style->font.as_font, style->text_style, width,
1547 										 height);
1548 	}
1549 }
1550