1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, see: <http://www.gnu.org/licenses/>
14  */
15 
16 /* IMPORTANT NOTE:
17  *
18  * The functions in this module *must not* assume that the geometries in the
19  * FvwmWindow structure reflect the desired geometry of the window or its
20  * parts.  While the window is resized or shaded, they may hold the old
21  * geometry instead of the new one (but you can not rely on this).  Therefore,
22  * these geometries must not be accessed directly or indirectly (by the
23  * functions from geometry,c).  Use the geometries that are passed in via
24  * structure pointers, e.d. "td".
25  */
26 
27 /* ---------------------------- included header files ---------------------- */
28 
29 #include "config.h"
30 
31 #include <stdio.h>
32 
33 #include "libs/fvwmlib.h"
34 #include "libs/Parse.h"
35 #include "libs/Graphics.h"
36 #include "libs/Picture.h"
37 #include "libs/PictureGraphics.h"
38 #include "libs/FRenderInit.h"
39 #include "libs/charmap.h"
40 #include "libs/wcontext.h"
41 #include "fvwm.h"
42 #include "execcontext.h"
43 #include "externs.h"
44 #include "misc.h"
45 #include "screen.h"
46 #include "geometry.h"
47 #include "borders.h"
48 #include "builtins.h"
49 #include "icons.h"
50 #include "frame.h"
51 
52 /* ---------------------------- local definitions -------------------------- */
53 
54 /* ---------------------------- local macros ------------------------------- */
55 
56 #define SWAP_ARGS(f,a1,a2) (f)?(a2):(a1),(f)?(a1):(a2)
57 
58 /* ---------------------------- imports ------------------------------------ */
59 
60 extern Window PressedW;
61 
62 /* ---------------------------- included code files ------------------------ */
63 
64 /* ---------------------------- local types -------------------------------- */
65 
66 typedef struct
67 {
68 	struct
69 	{
70 		unsigned use_pixmap : 1;
71 	} flags;
72 	Pixel pixel;
73 	struct
74 	{
75 		Pixmap p;
76 		Pixmap shape;
77 		Pixmap alpha;
78 		int depth;
79 		FvwmRenderAttributes fra;
80 		rectangle g;
81 		int stretch_w;
82 		int stretch_h;
83 		struct
84 		{
85 			unsigned is_tiled : 1;
86 			unsigned is_stretched : 1;
87 		} flags;
88 	} pixmap;
89 } pixmap_background_type;
90 
91 typedef struct
92 {
93 	Pixmap p;
94 	FvwmPicture *mp_created_pic;
95 	int cs;
96 	FvwmPicture *mp_pic;
97 	int mp_part;
98 	Bool created;
99 } bar_pixmap;
100 
101 typedef struct
102 {
103 	int count;
104 	bar_pixmap *bps;
105 } bar_bs_pixmaps;    /* for UseTitleStyle & Colorset */
106 
107 typedef struct
108 {
109 	Pixmap frame_pixmap;
110 	bar_bs_pixmaps bar_pixmaps[BS_MaxButtonState];
111 } dynamic_common_decorations;
112 
113 typedef struct
114 {
115 	int relief_width;
116 	GC relief_gc;
117 	GC shadow_gc;
118 	Pixel fore_color;
119 	Pixel back_color;
120 	int cs;
121 	int border_cs;		/* for UseBorderStyle */
122 	int bg_border_cs;	/* for UseBorderStyle */
123 	Pixmap back_pixmap;
124 	XSetWindowAttributes attributes;
125 	unsigned long valuemask;
126 	Pixmap texture_pixmap;
127 	int texture_pixmap_width;
128 	int texture_pixmap_height;
129 	XSetWindowAttributes notex_attributes;
130 	unsigned long notex_valuemask;
131 	dynamic_common_decorations dynamic_cd;
132 } common_decorations_type;
133 
134 typedef struct
135 {
136 	GC relief;
137 	GC shadow;
138 	GC transparent;
139 } draw_border_gcs;
140 
141 typedef struct
142 {
143 	int offset_tl;
144 	int offset_br;
145 	int thickness;
146 	int length;
147 	unsigned has_x_marks : 1;
148 	unsigned has_y_marks : 1;
149 } border_marks_descr;
150 
151 typedef struct
152 {
153 	int w_dout;
154 	int w_hiout;
155 	int w_trout;
156 	int w_c;
157 	int w_trin;
158 	int w_shin;
159 	int w_din;
160 	int sum;
161 	int trim;
162 	unsigned is_flat : 1;
163 } border_relief_size_descr;
164 
165 typedef struct
166 {
167 	rectangle sidebar_g;
168 	border_relief_size_descr relief;
169 	border_marks_descr marks;
170 	draw_border_gcs gcs;
171 } border_relief_descr;
172 
173 typedef struct
174 {
175 	unsigned pressed_bmask : NUMBER_OF_TITLE_BUTTONS;
176 	unsigned lit_bmask : NUMBER_OF_TITLE_BUTTONS;
177 	unsigned toggled_bmask : NUMBER_OF_TITLE_BUTTONS;
178 	unsigned clear_bmask : NUMBER_OF_TITLE_BUTTONS;
179 	unsigned draw_bmask : NUMBER_OF_TITLE_BUTTONS;
180 	unsigned max_bmask : NUMBER_OF_TITLE_BUTTONS;
181 	ButtonState bstate[NUMBER_OF_TITLE_BUTTONS];
182 	unsigned is_title_pressed : 1;
183 	unsigned is_title_lit : 1;
184 	unsigned do_clear_title : 1;
185 	ButtonState tstate;
186 } border_titlebar_state;
187 
188 typedef struct
189 {
190 	GC rgc;
191 	GC sgc;
192 	FlocaleWinString fstr;
193 	DecorFaceStyle *tstyle;
194 	DecorFace *df;
195 	unsigned is_toggled : 1;
196 } title_draw_descr;
197 
198 typedef struct
199 {
200 	common_decorations_type *cd;
201 	rectangle frame_g;
202 	rectangle bar_g;		/* titlebar geo vs the frame */
203 	rectangle left_buttons_g;	/* vs the frame */
204 	rectangle right_buttons_g;	/* vs the frame */
205 	frame_title_layout_t layout;
206 	frame_title_layout_t old_layout;
207 	border_titlebar_state tbstate;
208 	int length;			/* text */
209 	int offset;			/* text offset */
210 	/* MultiPixmap Geometries */
211 	rectangle under_text_g;		/* vs the titlebar */
212 	rectangle left_main_g;		/* vs the titlebar */
213 	rectangle right_main_g;		/* vs the titlebar */
214 	rectangle full_left_main_g;	/* vs the frame */
215 	rectangle full_right_main_g;	/* vs the frame */
216 	int left_end_length;
217 	int left_of_text_length;
218 	int right_end_length;
219 	int right_of_text_length;
220 	rotation_t draw_rotation;
221 	rotation_t restore_rotation;
222 	unsigned td_is_rotated : 1;
223 	unsigned has_been_saved : 1;
224 	unsigned has_vt : 1;		/* vertical title ? */
225 	unsigned has_an_upsidedown_rotation : 1;  /* 270 || 180 */
226 } titlebar_descr;
227 
228 /* ---------------------------- forward declarations ----------------------- */
229 /*  forward declarations are not so good */
230 
231 /* for grouping titlebar_descr computation */
232 static void border_rotate_titlebar_descr(FvwmWindow *fw, titlebar_descr *td);
233 
234 /* for grouping the MultiPixmap stuff */
235 static Bool border_mp_get_use_title_style_parts_and_geometry(
236 	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
237 	unsigned short sf, int is_left, rectangle *g, int *part);
238 
239 /* ---------------------------- local variables ---------------------------- */
240 
241 static const char ulgc[] = { 1, 0, 0, 0x7f, 2, 1, 1 };
242 static const char brgc[] = { 1, 1, 2, 0x7f, 0, 0, 3 };
243 
244 /* ---------------------------- exported variables (globals) --------------- */
245 
246 XGCValues Globalgcv;
247 unsigned long Globalgcm;
248 
249 /* ---------------------------- local functions ---------------------------- */
250 
is_button_toggled(FvwmWindow * fw,int button)251 static Bool is_button_toggled(
252 	FvwmWindow *fw, int button)
253 {
254 	mwm_flags mf;
255 
256 	if (!HAS_MWM_BUTTONS(fw))
257 	{
258 		return False;
259 	}
260 	mf = TB_MWM_DECOR_FLAGS(GetDecor(fw, buttons[button]));
261 	if ((mf & MWM_DECOR_MAXIMIZE) && IS_MAXIMIZED(fw))
262 	{
263 		return True;
264 	}
265 	if ((mf & MWM_DECOR_SHADE) && IS_SHADED(fw))
266 	{
267 		return True;
268 	}
269 	if ((mf & MWM_DECOR_STICK) &&
270 	    (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
271 	{
272 		return True;
273 	}
274 	if (TB_FLAGS(fw->decor->buttons[button]).has_layer &&
275 	    fw->layer == TB_LAYER(fw->decor->buttons[button]))
276 	{
277 		return True;
278 	}
279 
280 	return False;
281 }
282 
283 
284 /* rules to get button state */
border_flags_to_button_state(int is_pressed,int is_lit,int is_toggled)285 static ButtonState border_flags_to_button_state(
286 	int is_pressed, int is_lit, int is_toggled)
287 {
288 	if (!is_lit && Scr.gs.use_inactive_buttons)
289 	{
290 		if (is_pressed && Scr.gs.use_inactive_down_buttons)
291 		{
292 			return (is_toggled) ?
293 				BS_ToggledInactiveDown : BS_InactiveDown;
294 		}
295 		else
296 		{
297 			return (is_toggled) ?
298 				BS_ToggledInactiveUp : BS_InactiveUp;
299 		}
300 	}
301 	else
302 	{
303 		if (is_pressed && Scr.gs.use_active_down_buttons)
304 		{
305 			return (is_toggled) ?
306 				BS_ToggledActiveDown : BS_ActiveDown;
307 		}
308 		else
309 		{
310 			return (is_toggled) ?
311 				BS_ToggledActiveUp : BS_ActiveUp;
312 		}
313 	}
314 }
315 
get_common_decorations(common_decorations_type * cd,FvwmWindow * t,window_parts draw_parts,Bool has_focus,Bool is_border,Bool do_change_gcs)316 static void get_common_decorations(
317 	common_decorations_type *cd, FvwmWindow *t,
318 	window_parts draw_parts, Bool has_focus, Bool is_border,
319 	Bool do_change_gcs)
320 {
321 	DecorFace *df;
322 	color_quad *draw_colors;
323 
324 	df = border_get_border_style(t, has_focus);
325 	cd->bg_border_cs = -1;
326 	cd->cs = -1;
327 	if (has_focus)
328 	{
329 		/* are we using textured borders? */
330 		if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
331 		    GetDecor(t, BorderStyle.active.u.p->depth) == Pdepth)
332 		{
333 			cd->texture_pixmap = GetDecor(
334 				t, BorderStyle.active.u.p->picture);
335 			cd->texture_pixmap_width = GetDecor(
336 				t, BorderStyle.active.u.p->width);
337 			cd->texture_pixmap_height = GetDecor(
338 				t, BorderStyle.active.u.p->height);
339 		}
340 		else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
341 		{
342 			cd->bg_border_cs = GetDecor(
343 				t, BorderStyle.active.u.acs.cs);
344 		}
345 		cd->back_pixmap = Scr.gray_pixmap;
346 		if (is_border)
347 		{
348 			draw_colors = &(t->border_hicolors);
349 			cd->cs = t->border_cs_hi;
350 		}
351 		else
352 		{
353 			draw_colors = &(t->hicolors);
354 			cd->cs = t->cs_hi;
355 		}
356 	}
357 	else
358 	{
359 		if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
360 		    GetDecor(t, BorderStyle.inactive.u.p->depth) == Pdepth)
361 		{
362 			cd->texture_pixmap = GetDecor(
363 				t, BorderStyle.inactive.u.p->picture);
364 			cd->texture_pixmap_width = GetDecor(
365 				t, BorderStyle.inactive.u.p->width);
366 			cd->texture_pixmap_height = GetDecor(
367 				t, BorderStyle.inactive.u.p->height);
368 		}
369 		else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
370 		{
371 			cd->bg_border_cs = GetDecor(
372 				t, BorderStyle.inactive.u.acs.cs);
373 		}
374 		if (IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t))
375 		{
376 			cd->back_pixmap = Scr.sticky_gray_pixmap;
377 		}
378 		else
379 		{
380 			cd->back_pixmap = Scr.light_gray_pixmap;
381 		}
382 		if (is_border)
383 		{
384 			draw_colors = &(t->border_colors);
385 			cd->cs = t->border_cs;
386 		}
387 		else
388 		{
389 			draw_colors = &(t->colors);
390 			cd->cs = t->cs;
391 		}
392 	}
393 	cd->fore_color = draw_colors->fore;
394 	cd->back_color = draw_colors->back;
395 	if (do_change_gcs)
396 	{
397 		Globalgcv.foreground = draw_colors->hilight;
398 		Globalgcm = GCForeground;
399 		XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
400 		Globalgcv.foreground = draw_colors->shadow;
401 		XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
402 		cd->relief_gc = Scr.ScratchGC1;
403 		cd->shadow_gc = Scr.ScratchGC2;
404 	}
405 
406 	/* MWMBorder style means thin 3d effects */
407 	cd->relief_width = (HAS_MWM_BORDER(t) ? 1 : 2);
408 
409 	if (cd->texture_pixmap)
410 	{
411 		cd->attributes.background_pixmap = cd->texture_pixmap;
412 		cd->valuemask = CWBackPixmap;
413 	}
414 	else
415 	{
416 		if (Pdepth < 2)
417 		{
418 			cd->attributes.background_pixmap = cd->back_pixmap;
419 			cd->valuemask = CWBackPixmap;
420 		}
421 		else
422 		{
423 			cd->attributes.background_pixel = cd->back_color;
424 			cd->valuemask = CWBackPixel;
425 		}
426 	}
427 	if (Pdepth < 2)
428 	{
429 		cd->notex_attributes.background_pixmap = cd->back_pixmap;
430 		cd->notex_valuemask = CWBackPixmap;
431 	}
432 	else
433 	{
434 		cd->notex_attributes.background_pixel = cd->back_color;
435 		cd->notex_valuemask = CWBackPixel;
436 	}
437 
438 	return;
439 }
440 
border_get_changed_border_parts(FvwmWindow * fw,rectangle * old_sidebar_g,rectangle * new_sidebar_g,int cs)441 static window_parts border_get_changed_border_parts(
442 	FvwmWindow *fw, rectangle *old_sidebar_g, rectangle *new_sidebar_g,
443 	int cs)
444 {
445 	window_parts changed_parts;
446 
447 	changed_parts = PART_NONE;
448 	if (!CSET_IS_TRANSPARENT_PR(cs) && CSET_HAS_PIXMAP(cs) &&
449 	    (old_sidebar_g->x != new_sidebar_g->x ||
450 	     old_sidebar_g->y != new_sidebar_g->y ||
451 	     old_sidebar_g->width != new_sidebar_g->width ||
452 	     old_sidebar_g->height != new_sidebar_g->height))
453 	{
454 		/* optimizable? */
455 		changed_parts |= PART_FRAME;
456 		return changed_parts;
457 	}
458 	if (old_sidebar_g->x != new_sidebar_g->x)
459 	{
460 		changed_parts |= (PART_FRAME & (~PART_BORDER_W));
461 	}
462 	if (old_sidebar_g->y != new_sidebar_g->y)
463 	{
464 		changed_parts |= (PART_FRAME & (~PART_BORDER_N));
465 	}
466 	if (old_sidebar_g->width != new_sidebar_g->width)
467 	{
468 		changed_parts |=
469 			PART_BORDER_N | PART_BORDER_S;
470 		if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
471 		    TiledPixmapButton)
472 		{
473 			changed_parts |=
474 				PART_BORDER_NE | PART_BORDER_E | PART_BORDER_SE;
475 		}
476 	}
477 	if (old_sidebar_g->height != new_sidebar_g->height)
478 	{
479 		changed_parts |=
480 			PART_BORDER_W | PART_BORDER_E;
481 		if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
482 		    TiledPixmapButton)
483 		{
484 			changed_parts |=
485 				PART_BORDER_SW | PART_BORDER_S | PART_BORDER_SE;
486 		}
487 	}
488 
489 	return changed_parts;
490 }
491 
border_get_parts_and_pos_to_draw(common_decorations_type * cd,FvwmWindow * fw,window_parts pressed_parts,window_parts force_draw_parts,rectangle * old_g,rectangle * new_g,Bool do_hilight,border_relief_descr * br)492 static int border_get_parts_and_pos_to_draw(
493 	common_decorations_type *cd, FvwmWindow *fw,
494 	window_parts pressed_parts, window_parts force_draw_parts,
495 	rectangle *old_g, rectangle *new_g, Bool do_hilight,
496 	border_relief_descr *br)
497 {
498 	window_parts draw_parts;
499 	window_parts parts_to_light;
500 	rectangle sidebar_g_old;
501 	DecorFaceStyle *borderstyle;
502 	Bool has_x_marks;
503 	Bool has_x_marks_old;
504 	Bool has_y_marks;
505 	Bool has_y_marks_old;
506 	int cs = cd->bg_border_cs;
507 
508 	draw_parts = 0;
509 	borderstyle = (do_hilight) ?
510 		&GetDecor(fw, BorderStyle.active.style) :
511 		&GetDecor(fw, BorderStyle.inactive.style);
512 	frame_get_sidebar_geometry(
513 		fw, borderstyle,  new_g, &br->sidebar_g, &has_x_marks,
514 		&has_y_marks);
515 	if (has_x_marks == True)
516 	{
517 		draw_parts |= PART_X_HANDLES;
518 		br->marks.has_x_marks = 1;
519 	}
520 	else
521 	{
522 		br->marks.has_x_marks = 0;
523 	}
524 	if (has_y_marks == True)
525 	{
526 		draw_parts |= PART_Y_HANDLES;
527 		br->marks.has_y_marks = 1;
528 	}
529 	else
530 	{
531 		br->marks.has_y_marks = 0;
532 	}
533 	draw_parts |= (pressed_parts ^ fw->decor_state.parts_inverted);
534 	parts_to_light = (do_hilight == True) ? PART_FRAME : PART_NONE;
535 	draw_parts |= (parts_to_light ^ fw->decor_state.parts_lit);
536 	draw_parts |= (~(fw->decor_state.parts_drawn) & PART_FRAME);
537 	draw_parts |= force_draw_parts;
538 	if (old_g == NULL)
539 	{
540 		old_g = &fw->g.frame;
541 	}
542 	if ((draw_parts & PART_FRAME) == PART_FRAME)
543 	{
544 		draw_parts |= PART_FRAME;
545 		return draw_parts;
546 	}
547 	frame_get_sidebar_geometry(
548 		fw, borderstyle, old_g, &sidebar_g_old, &has_x_marks_old,
549 		&has_y_marks_old);
550 	if (has_x_marks_old != has_x_marks)
551 	{
552 		draw_parts |= (PART_FRAME & (~(PART_BORDER_N | PART_BORDER_S)));
553 	}
554 	if (has_y_marks_old != has_y_marks)
555 	{
556 		draw_parts |= (PART_FRAME & (~(PART_BORDER_W | PART_BORDER_E)));
557 	}
558 	draw_parts |= border_get_changed_border_parts(
559 		fw, &sidebar_g_old, &br->sidebar_g, cs);
560 	draw_parts &= (PART_FRAME | PART_HANDLES);
561 
562 	return draw_parts;
563 }
564 
border_get_tb_parts_to_draw(FvwmWindow * fw,titlebar_descr * td,rectangle * old_g,rectangle * new_g,window_parts force_draw_parts)565 static window_parts border_get_tb_parts_to_draw(
566 	FvwmWindow *fw, titlebar_descr *td, rectangle *old_g, rectangle *new_g,
567 	window_parts force_draw_parts)
568 {
569 	window_parts draw_parts;
570 	ButtonState old_state;
571 	int i;
572 	DecorFace *df,*tdf;
573 
574 	td->tbstate.draw_bmask = 0;
575 	draw_parts = PART_NONE;
576 	/* first time? */
577 	draw_parts |= (~(fw->decor_state.parts_drawn) & PART_TITLE);
578 	td->tbstate.draw_bmask |= (~(fw->decor_state.buttons_drawn));
579 	/* forced? */
580 	draw_parts |= force_draw_parts;
581 	td->tbstate.draw_bmask |= (force_draw_parts & PART_BUTTONS) ? ~0 : 0;
582 	/* check if state changed */
583 	old_state = border_flags_to_button_state(
584 		(fw->decor_state.parts_inverted & PART_TITLE),
585 		(fw->decor_state.parts_lit & PART_TITLE), 0);
586 	if (old_state != td->tbstate.tstate)
587 	{
588 		draw_parts |= PART_TITLE;
589 	}
590 	/* size changed? */
591 	if ((td->old_layout.title_g.width != td->layout.title_g.width ||
592 	     td->old_layout.title_g.height != td->layout.title_g.height) &&
593 	    td->layout.title_g.x >= 0 && td->layout.title_g.y >= 0)
594 	{
595 		draw_parts |= PART_TITLE;
596 	}
597 	/* same for buttons */
598 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
599 	{
600 		unsigned int mask = (1 << i);
601 
602 		if (FW_W_BUTTON(fw, i) == None)
603 		{
604 			continue;
605 		}
606 		old_state = border_flags_to_button_state(
607 			(fw->decor_state.buttons_inverted & mask),
608 			(fw->decor_state.buttons_lit & mask),
609 			(fw->decor_state.buttons_toggled & mask));
610 		if (old_state != td->tbstate.bstate[i])
611 		{
612 			draw_parts |= PART_BUTTONS;
613 			td->tbstate.draw_bmask |= mask;
614 		}
615 		if ((td->old_layout.button_g[i].width !=
616 		     td->layout.button_g[i].width ||
617 		     td->old_layout.button_g[i].height !=
618 		     td->layout.button_g[i].height) &&
619 		    td->layout.button_g[i].x >= 0 &&
620 		    td->layout.button_g[i].y >= 0)
621 		{
622 			draw_parts |= PART_BUTTONS;
623 			td->tbstate.draw_bmask |= mask;
624 		}
625 	}
626 	/* position changed and background is tiled or a cset? */
627 	if ((draw_parts & PART_TITLE) == PART_NONE &&
628 	    td->layout.title_g.x >= 0 &&
629 	    td->layout.title_g.y >= 0)
630 	{
631 		df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
632 		if (DFS_USE_BORDER_STYLE(df->style) &&
633 		    (((td->old_layout.title_g.x != td->layout.title_g.x ||
634 		       td->old_layout.title_g.y != td->layout.title_g.y) &&
635 		      ((td->cd->valuemask & CWBackPixmap) ||
636 		       CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
637 		     ||
638 		     (old_g->width != new_g->width &&
639 		      CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
640 		     ||
641 		     (old_g->height != new_g->height
642 		      && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
643 		     ||
644 		     ((old_g->x != new_g->x || old_g->y != new_g->y)
645 		      && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
646 		{
647 				draw_parts |= PART_TITLE;
648 		}
649 		if ((draw_parts & PART_TITLE) == PART_NONE &&
650 		    (old_g->x != new_g->x || old_g->y != new_g->y))
651 		{
652 			for (tdf = df; tdf != NULL; tdf = tdf->next)
653 			{
654 				if (DFS_FACE_TYPE(tdf->style) ==
655 				    ColorsetButton &&
656 				    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
657 				{
658 					draw_parts |= PART_TITLE;
659 					break;
660 				}
661 			}
662 		}
663 	}
664 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
665 	{
666 		unsigned int mask;
667 		DecorFaceStyle *bs;
668 
669 		mask = (1 << i);
670 		bs = &TB_STATE(
671 			GetDecor(fw, buttons[i]))[td->tbstate.bstate[i]].style;
672 		if ((td->tbstate.draw_bmask & mask) ||
673 		    td->layout.button_g[i].x < 0 ||
674 		    td->layout.button_g[i].y < 0)
675 		{
676 			continue;
677 		}
678 		if (DFS_USE_BORDER_STYLE(*bs) &&
679 		    (((td->old_layout.button_g[i].x !=
680 		       td->layout.button_g[i].x||
681 		       td->old_layout.button_g[i].y !=
682 		       td->layout.button_g[i].y)
683 		      && ((td->cd->valuemask & CWBackPixmap) ||
684 			  CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
685 		     ||
686 		     (old_g->width != new_g->width &&
687 		      CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
688 		     ||
689 		     (old_g->height != new_g->height
690 		      && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
691 		     ||
692 		     ((old_g->x != new_g->x || old_g->y != new_g->y)
693 		      && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
694 		{
695 			td->tbstate.draw_bmask |= mask;
696 		}
697 		else if (DFS_USE_TITLE_STYLE(*bs))
698 		{
699 			df = &TB_STATE(GetDecor(
700 				fw, titlebar))[td->tbstate.bstate[i]];
701 			for(tdf = df; tdf != NULL; tdf = tdf->next)
702 			{
703 				int cs;
704 				if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
705 				{
706 					/* can be improved */
707 					td->tbstate.draw_bmask |= mask;
708 					break;
709 				}
710 				if (DFS_FACE_TYPE(tdf->style) != ColorsetButton
711 				    || !CSET_HAS_PIXMAP(tdf->u.acs.cs))
712 				{
713 					continue;
714 				}
715 				cs = tdf->u.acs.cs;
716 				if(((td->old_layout.button_g[i].x !=
717 				     td->layout.button_g[i].x ||
718 				     td->old_layout.button_g[i].y !=
719 				     td->layout.button_g[i].y) ||
720 				    CSET_PIXMAP_IS_TILED(cs))
721 				   ||
722 				   (old_g->width != new_g->width &&
723 				    CSET_PIXMAP_IS_X_STRETCHED(cs))
724 				   ||
725 				   (old_g->height != new_g->height &&
726 				    CSET_PIXMAP_IS_Y_STRETCHED(cs))
727 					||
728 				   ((old_g->x != new_g->x ||
729 				     old_g->y != new_g->y)
730 				    && CSET_IS_TRANSPARENT_ROOT(cs)))
731 				{
732 					td->tbstate.draw_bmask |= mask;
733 					break;
734 				}
735 			}
736 		}
737 		if (td->tbstate.draw_bmask & mask)
738 		{
739 			continue;
740 		}
741 		if (old_g->x != new_g->x || old_g->y != new_g->y)
742 		{
743 			df = &TB_STATE(GetDecor(
744 				fw, buttons[i]))[td->tbstate.bstate[i]];
745 			for(tdf = df; tdf != NULL; tdf = tdf->next)
746 			{
747 				if (DFS_FACE_TYPE(tdf->style) ==
748 				    ColorsetButton &&
749 				    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
750 				{
751 					td->tbstate.draw_bmask |= mask;
752 					break;
753 				}
754 			}
755 		}
756 	}
757 	td->tbstate.max_bmask = 0;
758 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
759 	{
760 		if (FW_W_BUTTON(fw, i) == None)
761 		{
762 			continue;
763 		}
764 		if ((i & 1) == 1 && i / 2 < Scr.nr_right_buttons)
765 		{
766 			td->tbstate.max_bmask |= (1 << i);
767 		}
768 		else if ((i & 1) == 0 && i / 2 < Scr.nr_left_buttons)
769 		{
770 			td->tbstate.max_bmask |= (1 << i);
771 		}
772 	}
773 	td->tbstate.draw_bmask &= td->tbstate.max_bmask;
774 	td->tbstate.pressed_bmask &= td->tbstate.max_bmask;
775 	td->tbstate.lit_bmask &= td->tbstate.max_bmask;
776 	td->tbstate.toggled_bmask &= td->tbstate.max_bmask;
777 	td->tbstate.clear_bmask &= td->tbstate.max_bmask;
778 	if (td->tbstate.draw_bmask == 0)
779 	{
780 		draw_parts &= ~PART_BUTTONS;
781 	}
782 	else
783 	{
784 		draw_parts |= PART_BUTTONS;
785 	}
786 	draw_parts &= PART_TITLEBAR;
787 
788 	return draw_parts;
789 }
790 
border_get_border_gcs(draw_border_gcs * ret_gcs,common_decorations_type * cd,FvwmWindow * fw,Bool do_hilight)791 static void border_get_border_gcs(
792 	draw_border_gcs *ret_gcs, common_decorations_type *cd, FvwmWindow *fw,
793 	Bool do_hilight)
794 {
795 	static GC transparent_gc = None;
796 	DecorFaceStyle *borderstyle;
797 	Bool is_reversed = False;
798 
799 	if (transparent_gc == None && !HAS_NO_BORDER(fw) && !HAS_MWM_BORDER(fw))
800 	{
801 		XGCValues xgcv;
802 
803 		xgcv.function = GXnoop;
804 		xgcv.plane_mask = 0;
805 		transparent_gc = fvwmlib_XCreateGC(
806 			dpy, Scr.NoFocusWin, GCFunction | GCPlaneMask, &xgcv);
807 	}
808 	ret_gcs->transparent = transparent_gc;
809 	/* get the border style bits */
810 	borderstyle = (do_hilight) ?
811 		&GetDecor(fw, BorderStyle.active.style) :
812 		&GetDecor(fw, BorderStyle.inactive.style);
813 	if (borderstyle->flags.button_relief == DFS_BUTTON_IS_SUNK)
814 	{
815 		is_reversed = True;
816 	}
817 	if (is_reversed)
818 	{
819 		ret_gcs->shadow = cd->relief_gc;
820 		ret_gcs->relief = cd->shadow_gc;
821 	}
822 	else
823 	{
824 		ret_gcs->relief = cd->relief_gc;
825 		ret_gcs->shadow = cd->shadow_gc;
826 	}
827 
828 	return;
829 }
830 
trim_border_layout(FvwmWindow * fw,DecorFaceStyle * borderstyle,border_relief_size_descr * ret_size_descr)831 static void trim_border_layout(
832 	FvwmWindow *fw, DecorFaceStyle *borderstyle,
833 	border_relief_size_descr *ret_size_descr)
834 {
835 	/* If the border is too thin to accomodate the standard look, we remove
836 	 * parts of the border so that at least one pixel of the original
837 	 * colour is visible. We make an exception for windows with a border
838 	 * width of 2, though. */
839 	if ((!IS_SHADED(fw) || HAS_TITLE(fw)) && fw->boundary_width == 2)
840 	{
841 		ret_size_descr->trim--;
842 	}
843 	if (ret_size_descr->trim < 0)
844 	{
845 		ret_size_descr->trim = 0;
846 	}
847 	for ( ; ret_size_descr->trim > 0; ret_size_descr->trim--)
848 	{
849 		if (ret_size_descr->w_hiout > 1)
850 		{
851 			ret_size_descr->w_hiout--;
852 		}
853 		else if (ret_size_descr->w_shin > 0)
854 		{
855 			ret_size_descr->w_shin--;
856 		}
857 		else if (ret_size_descr->w_hiout > 0)
858 		{
859 			ret_size_descr->w_hiout--;
860 		}
861 		else if (ret_size_descr->w_trout > 0)
862 		{
863 			ret_size_descr->w_trout = 0;
864 			ret_size_descr->w_trin = 0;
865 			ret_size_descr->w_din = 0;
866 			ret_size_descr->w_hiout = 1;
867 		}
868 		ret_size_descr->sum--;
869 	}
870 	ret_size_descr->w_c = fw->boundary_width - ret_size_descr->sum;
871 
872 	return;
873 }
874 
check_remove_inset(DecorFaceStyle * borderstyle,border_relief_size_descr * ret_size_descr)875 static void check_remove_inset(
876 	DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr)
877 {
878 	if (!DFS_HAS_NO_INSET(*borderstyle))
879 	{
880 		return;
881 	}
882 	ret_size_descr->w_shin = 0;
883 	ret_size_descr->sum--;
884 	ret_size_descr->trim--;
885 	if (ret_size_descr->w_trin)
886 	{
887 		ret_size_descr->w_trout = 0;
888 		ret_size_descr->w_trin = 0;
889 		ret_size_descr->w_din = 0;
890 		ret_size_descr->w_hiout = 1;
891 		ret_size_descr->sum -= 2;
892 		ret_size_descr->trim -= 2;
893 	}
894 
895 	return;
896 }
897 
border_fetch_mwm_layout(FvwmWindow * fw,DecorFaceStyle * borderstyle,border_relief_size_descr * ret_size_descr)898 static void border_fetch_mwm_layout(
899 	FvwmWindow *fw, DecorFaceStyle *borderstyle,
900 	border_relief_size_descr *ret_size_descr)
901 {
902 	/* MWM borders look like this:
903 	 *
904 	 * HHCCCCS  from outside to inside on the left and top border
905 	 * SSCCCCH  from outside to inside on the bottom and right border
906 	 * |||||||
907 	 * |||||||__ w_shin	(inner shadow area)
908 	 * ||||||___ w_c	(transparent area)
909 	 * |||||____ w_c	(transparent area)
910 	 * ||||_____ w_c	(transparent area)
911 	 * |||______ w_c	(transparent area)
912 	 * ||_______ w_hiout	(outer hilight area)
913 	 * |________ w_hiout	(outer hilight area)
914 	 *
915 	 *
916 	 * C = original colour
917 	 * H = hilight
918 	 * S = shadow
919 	 */
920 	ret_size_descr->w_dout = 0;
921 	ret_size_descr->w_hiout = 2;
922 	ret_size_descr->w_trout = 0;
923 	ret_size_descr->w_trin = 0;
924 	ret_size_descr->w_shin = 1;
925 	ret_size_descr->w_din = 0;
926 	ret_size_descr->sum = 3;
927 	ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width + 1;
928 	check_remove_inset(borderstyle, ret_size_descr);
929 	trim_border_layout(fw, borderstyle, ret_size_descr);
930 
931 	return;
932 }
933 
border_fetch_fvwm_layout(FvwmWindow * fw,DecorFaceStyle * borderstyle,border_relief_size_descr * ret_size_descr)934 static void border_fetch_fvwm_layout(
935 	FvwmWindow *fw, DecorFaceStyle *borderstyle,
936 	border_relief_size_descr *ret_size_descr)
937 {
938 	/* Fvwm borders look like this:
939 	 *
940 	 * SHHCCSS  from outside to inside on the left and top border
941 	 * SSCCHHS  from outside to inside on the bottom and right border
942 	 * |||||||
943 	 * |||||||__ w_din	(inner dark area)
944 	 * ||||||___ w_shin	(inner shadow area)
945 	 * |||||____ w_trin	(inner transparent/shadow area)
946 	 * ||||_____ w_c	(transparent area)
947 	 * |||______ w_trout	(outer transparent/hilight area)
948 	 * ||_______ w_hiout	(outer hilight area)
949 	 * |________ w_dout	(outer dark area)
950 	 *
951 	 * C = original colour
952 	 * H = hilight
953 	 * S = shadow
954 	 *
955 	 * reduced to 5 pixels it looks like this:
956 	 *
957 	 * SHHCS
958 	 * SSCHS
959 	 * |||||
960 	 * |||||__ w_din	(inner dark area)
961 	 * ||||___ w_trin	(inner transparent/shadow area)
962 	 * |||____ w_trout	(outer transparent/hilight area)
963 	 * ||_____ w_hiout	(outer hilight area)
964 	 * |______ w_dout	(outer dark area)
965 	 */
966 	ret_size_descr->w_dout = 1;
967 	ret_size_descr->w_hiout = 1;
968 	ret_size_descr->w_trout = 1;
969 	ret_size_descr->w_trin = 1;
970 	ret_size_descr->w_shin = 1;
971 	ret_size_descr->w_din = 1;
972 	/* w_trout + w_trin counts only as one pixel of border because
973 	 * they let one pixel of the original colour shine through. */
974 	ret_size_descr->sum = 6;
975 	ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width;
976 	check_remove_inset(borderstyle, ret_size_descr);
977 	trim_border_layout(fw, borderstyle, ret_size_descr);
978 
979 	return;
980 }
981 
border_get_border_relief_size_descr(border_relief_size_descr * ret_size_descr,FvwmWindow * fw,Bool do_hilight)982 static void border_get_border_relief_size_descr(
983 	border_relief_size_descr *ret_size_descr, FvwmWindow *fw,
984 	Bool do_hilight)
985 {
986 	DecorFaceStyle *borderstyle;
987 
988 	if (is_window_border_minimal(fw))
989 	{
990 		/* the border is too small, only a background but no relief */
991 		ret_size_descr->is_flat = 1;
992 		return;
993 	}
994 	borderstyle = (do_hilight) ?
995 		&GetDecor(fw, BorderStyle.active.style) :
996 		&GetDecor(fw, BorderStyle.inactive.style);
997 	if (borderstyle->flags.button_relief == DFS_BUTTON_IS_FLAT)
998 	{
999 		ret_size_descr->is_flat = 1;
1000 		return;
1001 	}
1002 	ret_size_descr->is_flat = 0;
1003 	/* get the relief layout */
1004 	if (HAS_MWM_BORDER(fw))
1005 	{
1006 		border_fetch_mwm_layout(fw, borderstyle, ret_size_descr);
1007 	}
1008 	else
1009 	{
1010 		border_fetch_fvwm_layout(fw, borderstyle, ret_size_descr);
1011 	}
1012 
1013 	return;
1014 }
1015 
border_get_border_marks_descr(common_decorations_type * cd,border_relief_descr * br,FvwmWindow * fw)1016 static void border_get_border_marks_descr(
1017 	common_decorations_type *cd, border_relief_descr *br, FvwmWindow *fw)
1018 {
1019 	int inset;
1020 
1021 	/* get mark's length and thickness */
1022 	inset = (br->relief.w_shin != 0 || br->relief.w_din != 0);
1023 	br->marks.length = fw->boundary_width - br->relief.w_dout - inset;
1024 	if (br->marks.length <= 0)
1025 	{
1026 		br->marks.has_x_marks = 0;
1027 		br->marks.has_y_marks = 0;
1028 		return;
1029 	}
1030 	br->marks.thickness = cd->relief_width;
1031 	if (br->marks.thickness > br->marks.length)
1032 	{
1033 		br->marks.thickness = br->marks.length;
1034 	}
1035 	/* get offsets from outer side of window */
1036 	br->marks.offset_tl = br->relief.w_dout;
1037 	br->marks.offset_br =
1038 		-br->relief.w_dout - br->marks.length - br->marks.offset_tl;
1039 
1040 	return;
1041 }
1042 
border_create_decor_pixmap(common_decorations_type * cd,rectangle * decor_g)1043 static Pixmap border_create_decor_pixmap(
1044 	common_decorations_type *cd, rectangle *decor_g)
1045 {
1046 	Pixmap p;
1047 
1048 	p = XCreatePixmap(
1049 		dpy, Scr.Root, decor_g->width, decor_g->height, Pdepth);
1050 
1051 	return p;
1052 }
1053 
border_draw_part_relief(border_relief_descr * br,rectangle * frame_g,rectangle * part_g,Pixmap dest_pix,Bool is_inverted)1054 static void border_draw_part_relief(
1055 	border_relief_descr *br, rectangle *frame_g, rectangle *part_g,
1056 	Pixmap dest_pix, Bool is_inverted)
1057 {
1058 	int i;
1059 	int off_x = 0;
1060 	int off_y = 0;
1061 	int width = frame_g->width - 1;
1062 	int height = frame_g->height - 1;
1063 	int w[7];
1064 	GC gc[4];
1065 
1066 	w[0] = br->relief.w_dout;
1067 	w[1] = br->relief.w_hiout;
1068 	w[2] = br->relief.w_trout;
1069 	w[3] = br->relief.w_c;
1070 	w[4] = br->relief.w_trin;
1071 	w[5] = br->relief.w_shin;
1072 	w[6] = br->relief.w_din;
1073 	gc[(is_inverted == True)] = br->gcs.relief;
1074 	gc[!(is_inverted == True)] = br->gcs.shadow;
1075 	gc[2] = br->gcs.transparent;
1076 	gc[3] = br->gcs.shadow;
1077 
1078 	off_x = -part_g->x;
1079 	off_y = -part_g->y;
1080 	width = frame_g->width - 1;
1081 	height = frame_g->height - 1;
1082 	for (i = 0; i < 7; i++)
1083 	{
1084 		if (ulgc[i] != 0x7f && w[i] > 0)
1085 		{
1086 			do_relieve_rectangle(
1087 				dpy, dest_pix, off_x, off_y,
1088 				width, height, gc[(int)ulgc[i]],
1089 				gc[(int)brgc[i]], w[i], False);
1090 		}
1091 		off_x += w[i];
1092 		off_y += w[i];
1093 		width -= 2 * w[i];
1094 		height -= 2 * w[i];
1095 	}
1096 
1097 	return;
1098 }
1099 
border_draw_x_mark(border_relief_descr * br,int x,int y,Pixmap dest_pix,Bool do_draw_shadow)1100 static void border_draw_x_mark(
1101 	border_relief_descr *br, int x, int y, Pixmap dest_pix,
1102 	Bool do_draw_shadow)
1103 {
1104 	int k;
1105 	int length;
1106 	GC gc;
1107 
1108 	if (br->marks.has_x_marks == 0)
1109 	{
1110 		return;
1111 	}
1112 	x += br->marks.offset_tl;
1113 	gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
1114 	/* draw it */
1115 	for (k = 0, length = br->marks.length - 1; k < br->marks.thickness;
1116 	     k++, length--)
1117 	{
1118 		int x1;
1119 		int x2;
1120 		int y1;
1121 		int y2;
1122 
1123 		if (length < 0)
1124 		{
1125 			break;
1126 		}
1127 		if (do_draw_shadow)
1128 		{
1129 			x1 = x + k;
1130 			y1 = y - 1 - k;
1131 		}
1132 		else
1133 		{
1134 			x1 = x;
1135 			y1 = y + k;
1136 		}
1137 		x2 = x1 + length;
1138 		y2 = y1;
1139 		XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
1140 	}
1141 
1142 	return;
1143 }
1144 
border_draw_y_mark(border_relief_descr * br,int x,int y,Pixmap dest_pix,Bool do_draw_shadow)1145 static void border_draw_y_mark(
1146 	border_relief_descr *br, int x, int y, Pixmap dest_pix,
1147 	Bool do_draw_shadow)
1148 {
1149 	int k;
1150 	int length;
1151 	GC gc;
1152 
1153 	if (br->marks.has_y_marks == 0)
1154 	{
1155 		return;
1156 	}
1157 	y += br->marks.offset_tl;
1158 	gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
1159 	/* draw it */
1160 	for (k = 0, length = br->marks.length; k < br->marks.thickness;
1161 	     k++, length--)
1162 	{
1163 		int x1;
1164 		int x2;
1165 		int y1;
1166 		int y2;
1167 
1168 		if (length <= 0)
1169 		{
1170 			break;
1171 		}
1172 		if (do_draw_shadow)
1173 		{
1174 			x1 = x - 1 - k;
1175 			y1 = y + k;
1176 		}
1177 		else
1178 		{
1179 			x1 = x + k;
1180 			y1 = y;
1181 		}
1182 		x2 = x1;
1183 		y2 = y1 + length - 1;
1184 		XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
1185 	}
1186 
1187 	return;
1188 }
1189 
border_draw_part_marks(border_relief_descr * br,rectangle * part_g,window_parts part,Pixmap dest_pix)1190 static void border_draw_part_marks(
1191 	border_relief_descr *br, rectangle *part_g, window_parts part,
1192 	Pixmap dest_pix)
1193 {
1194 	int l;
1195 	int t;
1196 	int w;
1197 	int h;
1198 	int o;
1199 
1200 	l = br->sidebar_g.x;
1201 	t = br->sidebar_g.y;
1202 	w = part_g->width;
1203 	h = part_g->height;
1204 	o = br->marks.offset_br;
1205 	switch (part)
1206 	{
1207 	case PART_BORDER_N:
1208 		border_draw_y_mark(br, 0, 0, dest_pix, False);
1209 		border_draw_y_mark(br, w, 0, dest_pix, True);
1210 		break;
1211 	case PART_BORDER_S:
1212 		border_draw_y_mark(br, 0, h + o, dest_pix, False);
1213 		border_draw_y_mark(br, w, h + o, dest_pix, True);
1214 		break;
1215 	case PART_BORDER_E:
1216 		border_draw_x_mark(br, w + o, 0, dest_pix, False);
1217 		border_draw_x_mark(br, w + o, h, dest_pix, True);
1218 		break;
1219 	case PART_BORDER_W:
1220 		border_draw_x_mark(br, 0, 0, dest_pix, False);
1221 		border_draw_x_mark(br, 0, h, dest_pix, True);
1222 		break;
1223 	case PART_BORDER_NW:
1224 		border_draw_x_mark(br, 0, t, dest_pix, True);
1225 		border_draw_y_mark(br, l, 0, dest_pix, True);
1226 		break;
1227 	case PART_BORDER_NE:
1228 		border_draw_x_mark(br, l + o, t, dest_pix, True);
1229 		border_draw_y_mark(br, 0, 0, dest_pix, False);
1230 		break;
1231 	case PART_BORDER_SW:
1232 		border_draw_x_mark(br, 0, 0, dest_pix, False);
1233 		border_draw_y_mark(br, l, t + o, dest_pix, True);
1234 		break;
1235 	case PART_BORDER_SE:
1236 		border_draw_x_mark(br, l + o, 0, dest_pix, False);
1237 		border_draw_y_mark(br, 0, t + o, dest_pix, False);
1238 		break;
1239 	default:
1240 		return;
1241 	}
1242 
1243 	return;
1244 }
1245 
border_set_part_background(Window w,Pixmap pix)1246 inline static void border_set_part_background(
1247 	Window w, Pixmap pix)
1248 {
1249 	XSetWindowAttributes xswa;
1250 
1251 	xswa.background_pixmap = pix;
1252 	XChangeWindowAttributes(dpy, w, CWBackPixmap, &xswa);
1253 
1254 	return;
1255 }
1256 
1257 /* render the an image into the pixmap */
border_fill_pixmap_background(Pixmap dest_pix,rectangle * dest_g,pixmap_background_type * bg,common_decorations_type * cd)1258 static void border_fill_pixmap_background(
1259 	Pixmap dest_pix, rectangle *dest_g, pixmap_background_type *bg,
1260 	common_decorations_type *cd)
1261 {
1262 	Bool do_tile;
1263 	Bool do_stretch;
1264 	XGCValues xgcv;
1265 	unsigned long valuemask;
1266 	Pixmap p = None, shape = None, alpha = None;
1267 	int src_width, src_height;
1268 
1269 	do_tile = (bg->flags.use_pixmap && bg->pixmap.flags.is_tiled) ?
1270 		True : False;
1271 	do_stretch = (bg->flags.use_pixmap && bg->pixmap.flags.is_stretched) ?
1272 		True : False;
1273 	xgcv.fill_style = FillSolid;
1274 	valuemask = GCFillStyle;
1275 	if (!bg->flags.use_pixmap)
1276 	{
1277 		/* solid pixel */
1278 		xgcv.foreground = bg->pixel;
1279 		xgcv.clip_x_origin = 0;
1280 		xgcv.clip_y_origin = 0;
1281 		xgcv.clip_mask = None;
1282 		valuemask |= GCForeground | GCClipMask | GCClipXOrigin |
1283 			GCClipYOrigin;
1284 		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1285 		XFillRectangle(
1286 			dpy, dest_pix, Scr.BordersGC, dest_g->x, dest_g->y,
1287 			dest_g->width - dest_g->x, dest_g->height - dest_g->y);
1288 		return;
1289 	}
1290 
1291 	if (do_stretch)
1292 	{
1293 		if (bg->pixmap.p)
1294 		{
1295 			p = CreateStretchPixmap(
1296 				dpy, bg->pixmap.p,
1297 				bg->pixmap.g.width, bg->pixmap.g.height,
1298 				bg->pixmap.depth,
1299 				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1300 				(bg->pixmap.depth == 1)?
1301 				Scr.MonoGC:Scr.BordersGC);
1302 		}
1303 		if (bg->pixmap.shape)
1304 		{
1305 			shape = CreateStretchPixmap(
1306 				dpy, bg->pixmap.shape,
1307 				bg->pixmap.g.width, bg->pixmap.g.height, 1,
1308 				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1309 				Scr.MonoGC);
1310 		}
1311 		if (bg->pixmap.alpha)
1312 		{
1313 			alpha = CreateStretchPixmap(
1314 				dpy, bg->pixmap.alpha,
1315 				bg->pixmap.g.width, bg->pixmap.g.height,
1316 				FRenderGetAlphaDepth(),
1317 				bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1318 				Scr.AlphaGC);
1319 		}
1320 		src_width = bg->pixmap.stretch_w;
1321 		src_height = bg->pixmap.stretch_h;
1322 	}
1323 	else
1324 	{
1325 		p = bg->pixmap.p;
1326 		shape = bg->pixmap.shape;
1327 		alpha =	bg->pixmap.alpha;
1328 		src_width = bg->pixmap.g.width;
1329 		src_height = bg->pixmap.g.height;
1330 	}
1331 
1332 	if (do_tile == False)
1333 	{
1334 		/* pixmap, offset stored in dest_g->x/y */
1335 		xgcv.foreground = cd->fore_color;
1336 		xgcv.background = cd->back_color;
1337 		valuemask |= GCForeground|GCBackground;
1338 		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1339 		PGraphicsRenderPixmaps(
1340 			dpy, Scr.NoFocusWin, p, shape, alpha,
1341 			bg->pixmap.depth, &(bg->pixmap.fra),
1342 			dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
1343 			bg->pixmap.g.x, bg->pixmap.g.y,
1344 			src_width, src_height,
1345 			dest_g->x, dest_g->y, dest_g->width - dest_g->x,
1346 			dest_g->height - dest_g->y, False);
1347 	}
1348 	else
1349 	{
1350 		/* tiled pixmap */
1351 		xgcv.foreground = cd->fore_color;
1352 		xgcv.background = cd->back_color;
1353 		valuemask |= GCForeground|GCBackground;
1354 		XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1355 		PGraphicsRenderPixmaps(
1356 			dpy, Scr.NoFocusWin, p, shape, alpha,
1357 			bg->pixmap.depth, &(bg->pixmap.fra),
1358 			dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
1359 			bg->pixmap.g.x, bg->pixmap.g.y,
1360 			src_width, src_height,
1361 			dest_g->x, dest_g->y,
1362 			dest_g->width - dest_g->x,
1363 			dest_g->height - dest_g->y, True);
1364 	}
1365 	if (p && p != bg->pixmap.p)
1366 	{
1367 		XFreePixmap(dpy, p);
1368 	}
1369 	if (shape && shape != bg->pixmap.shape)
1370 	{
1371 		XFreePixmap(dpy, shape);
1372 	}
1373 	if (alpha && alpha != bg->pixmap.alpha)
1374 	{
1375 		XFreePixmap(dpy, alpha);
1376 	}
1377 	return;
1378 }
1379 
1380 /* create a root transparent colorset bg, we take in account a possible
1381  * drawing rotation */
border_create_root_transparent_pixmap(titlebar_descr * td,Window w,int width,int height,int cs)1382 static Pixmap border_create_root_transparent_pixmap(
1383 	titlebar_descr *td, Window w, int width, int height, int cs)
1384 {
1385 	int my_w, my_h;
1386 	Pixmap p;
1387 
1388 	if (!CSET_IS_TRANSPARENT_ROOT(cs))
1389 	{
1390 		return None;
1391 	}
1392 	if (td->td_is_rotated &&
1393 	    (td->draw_rotation == ROTATION_90 ||
1394 	     td->draw_rotation == ROTATION_270))
1395 	{
1396 		my_h = width;
1397 		my_w = height;
1398 	}
1399 	else
1400 	{
1401 		my_w = width;
1402 		my_h = height;
1403 	}
1404 	p = CreateBackgroundPixmap(
1405 		dpy, w, my_w, my_h, &Colorset[cs],
1406 		Pdepth, Scr.BordersGC, False);
1407 	if (p && td->td_is_rotated)
1408 	{
1409 		Pixmap tmp;
1410 		tmp = CreateRotatedPixmap(
1411 			dpy, p, my_w, my_h, Pdepth, Scr.BordersGC,
1412 			td->restore_rotation);
1413 		XFreePixmap(dpy, p);
1414 		p = tmp;
1415 	}
1416 	return p;
1417 }
1418 
border_get_frame_pixmap(common_decorations_type * cd,rectangle * frame_g)1419 static void border_get_frame_pixmap(
1420 	common_decorations_type *cd, rectangle *frame_g)
1421 {
1422 	dynamic_common_decorations *dcd = &(cd->dynamic_cd);
1423 
1424 	if (dcd->frame_pixmap != None)
1425 	{
1426 		/* should not happen */
1427 		fvwm_debug(__func__, "Bad use of border_get_frame_pixmap!!\n");
1428 		dcd->frame_pixmap = None;
1429 	}
1430 
1431 	if (cd->bg_border_cs < 0 || CSET_IS_TRANSPARENT(cd->bg_border_cs))
1432 	{
1433 		/* should not happen */
1434 	}
1435 	else
1436 	{
1437 		dcd->frame_pixmap = CreateBackgroundPixmap(
1438 			dpy, Scr.NoFocusWin, frame_g->width, frame_g->height,
1439 			&Colorset[cd->bg_border_cs], Pdepth, Scr.BordersGC,
1440 			False);
1441 	}
1442 	return;
1443 }
1444 
border_get_border_background(pixmap_background_type * bg,common_decorations_type * cd,rectangle * part_g,rectangle * relative_g,int * free_bg_pixmap,Window w)1445 static void border_get_border_background(
1446 	pixmap_background_type *bg, common_decorations_type *cd,
1447 	rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window w)
1448 {
1449 	*free_bg_pixmap = False;
1450 
1451 	if (cd->texture_pixmap)
1452 	{
1453 		bg->flags.use_pixmap = 1;
1454 		bg->pixmap.p = cd->texture_pixmap;
1455 		bg->pixmap.g.width = cd->texture_pixmap_width;
1456 		bg->pixmap.g.height = cd->texture_pixmap_height;
1457 		bg->pixmap.shape = None;
1458 		bg->pixmap.alpha = None;
1459 		bg->pixmap.depth = Pdepth;
1460 		bg->pixmap.flags.is_tiled = 1;
1461 		bg->pixmap.flags.is_stretched = 0;
1462 		bg->pixmap.fra.mask = 0;
1463 	}
1464 	else if (cd->bg_border_cs >= 0 &&
1465 		 !CSET_IS_TRANSPARENT_PR(cd->bg_border_cs))
1466 	{
1467 		colorset_t *cs_t = &Colorset[cd->bg_border_cs];
1468 		XGCValues xgcv;
1469 
1470 		if (CSET_IS_TRANSPARENT_ROOT(cd->bg_border_cs))
1471 		{
1472 			bg->pixmap.p = CreateBackgroundPixmap(
1473 				dpy, w, part_g->width, part_g->height, cs_t,
1474 				Pdepth, Scr.BordersGC, False);
1475 		}
1476 		else
1477 		{
1478 			/* FIXME */
1479 			if (cd->dynamic_cd.frame_pixmap == None)
1480 			{
1481 				border_get_frame_pixmap(cd, relative_g);
1482 			}
1483 			bg->pixmap.p = XCreatePixmap(
1484 				dpy, cd->dynamic_cd.frame_pixmap, part_g->width,
1485 				part_g->height, Pdepth);
1486 			xgcv.fill_style = FillTiled;
1487 			xgcv.tile = cd->dynamic_cd.frame_pixmap;
1488 			xgcv.ts_x_origin = - relative_g->x;
1489 			xgcv.ts_y_origin = - relative_g->y;
1490 			XChangeGC(
1491 				dpy, Scr.BordersGC, GCTile | GCTileStipXOrigin |
1492 				GCTileStipYOrigin | GCFillStyle, &xgcv);
1493 			XFillRectangle(
1494 				dpy, bg->pixmap.p, Scr.BordersGC, 0, 0,
1495 				part_g->width, part_g->height);
1496 			xgcv.fill_style = FillSolid;
1497 			XChangeGC(dpy, Scr.BordersGC, GCFillStyle, &xgcv);
1498 		}
1499 		bg->pixmap.g.width = part_g->width;
1500 		bg->pixmap.g.height = part_g->height;
1501 		bg->flags.use_pixmap = 1;
1502 		bg->pixmap.shape = None;
1503 		bg->pixmap.alpha = None;
1504 		bg->pixmap.depth = Pdepth;
1505 		bg->pixmap.flags.is_tiled = 1;
1506 		bg->pixmap.flags.is_stretched = 0;
1507 		bg->pixmap.fra.mask = 0;
1508 		*free_bg_pixmap = True;
1509 	}
1510 	else
1511 	{
1512 		bg->flags.use_pixmap = 0;
1513 		bg->pixel = cd->attributes.background_pixel;
1514 	}
1515 
1516 	return;
1517 }
1518 
border_draw_one_border_part(common_decorations_type * cd,FvwmWindow * fw,rectangle * sidebar_g,rectangle * frame_g,border_relief_descr * br,window_parts part,window_parts draw_handles,Bool is_inverted,Bool do_clear)1519 static void border_draw_one_border_part(
1520 	common_decorations_type *cd, FvwmWindow *fw, rectangle *sidebar_g,
1521 	rectangle *frame_g, border_relief_descr *br, window_parts part,
1522 	window_parts draw_handles, Bool is_inverted, Bool do_clear)
1523 {
1524 	pixmap_background_type bg;
1525 	rectangle part_g;
1526 	rectangle pix_g;
1527 	rectangle relative_g;
1528 	Pixmap p;
1529 	Window w;
1530 	Bool free_bg_pixmap = False;
1531 
1532 	/* make a pixmap */
1533 	border_get_part_geometry(fw, part, sidebar_g, &part_g, &w);
1534 	if (part_g.width <= 0 || part_g.height <= 0)
1535 	{
1536 		return;
1537 	}
1538 	p = border_create_decor_pixmap(cd, &part_g);
1539 	/* set the background tile */
1540 	relative_g.width = fw->g.frame.width;
1541 	relative_g.height = fw->g.frame.height;
1542 	relative_g.x = part_g.x;
1543 	relative_g.y = part_g.y;
1544 	border_get_border_background(
1545 		&bg, cd, &part_g, &relative_g, &free_bg_pixmap, w);
1546 	if (cd->texture_pixmap)
1547 	{
1548 		switch (part)
1549 		{
1550 		case PART_BORDER_E:
1551 			bg.pixmap.g.x = frame_g->width - fw->boundary_width;
1552 			break;
1553 		case PART_BORDER_NE:
1554 		case PART_BORDER_SE:
1555 			bg.pixmap.g.x = frame_g->width - fw->corner_width;
1556 			break;
1557 		case PART_BORDER_N:
1558 		case PART_BORDER_S:
1559 			bg.pixmap.g.x = fw->corner_width;
1560 			break;
1561 		default:
1562 			bg.pixmap.g.x = 0;
1563 			break;
1564 		}
1565 		switch (part)
1566 		{
1567 		case PART_BORDER_S:
1568 			bg.pixmap.g.y = frame_g->height - fw->boundary_width;
1569 			break;
1570 		case PART_BORDER_SW:
1571 		case PART_BORDER_SE:
1572 			bg.pixmap.g.y = frame_g->height - fw->corner_width;
1573 			break;
1574 		case PART_BORDER_W:
1575 		case PART_BORDER_E:
1576 			bg.pixmap.g.y = fw->corner_width;
1577 			break;
1578 		default:
1579 			bg.pixmap.g.y = 0;
1580 			break;
1581 		}
1582 	}
1583 	else
1584 	{
1585 		bg.pixmap.g.x = 0;
1586 		bg.pixmap.g.y = 0;
1587 	}
1588 	/* set the geometry for drawing the Tiled pixmap; maybe add the relief
1589 	 * as offset? */
1590 	pix_g.x = 0;
1591 	pix_g.y = 0;
1592 	pix_g.width = part_g.width;
1593 	pix_g.height = part_g.height;
1594 	border_fill_pixmap_background(p, &pix_g, &bg, cd);
1595 	if (free_bg_pixmap && bg.pixmap.p)
1596 	{
1597 		XFreePixmap(dpy, bg.pixmap.p);
1598 	}
1599 	/* draw the relief over the background */
1600 	if (!br->relief.is_flat)
1601 	{
1602 		border_draw_part_relief(br, frame_g, &part_g, p, is_inverted);
1603 		/* draw the handle marks */
1604 		if (br->marks.has_x_marks || br->marks.has_y_marks)
1605 		{
1606 			border_draw_part_marks(br, &part_g, part, p);
1607 		}
1608 	}
1609 	/* apply the pixmap and destroy it */
1610 	border_set_part_background(w, p);
1611 	if (do_clear == True)
1612 	{
1613 		XClearWindow(dpy,w);
1614 	}
1615 	XFreePixmap(dpy, p);
1616 
1617 	return;
1618 }
1619 
border_draw_all_border_parts(common_decorations_type * cd,FvwmWindow * fw,border_relief_descr * br,rectangle * frame_g,window_parts draw_parts,window_parts pressed_parts,Bool do_hilight,Bool do_clear)1620 static void border_draw_all_border_parts(
1621 	common_decorations_type *cd, FvwmWindow *fw, border_relief_descr *br,
1622 	rectangle *frame_g, window_parts draw_parts,
1623 	window_parts pressed_parts, Bool do_hilight, Bool do_clear)
1624 {
1625 	window_parts part;
1626 	window_parts draw_handles;
1627 
1628 	/* get the description of the drawing directives */
1629 	border_get_border_relief_size_descr(&br->relief, fw, do_hilight);
1630 	border_get_border_marks_descr(cd, br, fw);
1631 	/* fetch the gcs used to draw the border */
1632 	border_get_border_gcs(&br->gcs, cd, fw, do_hilight);
1633 	/* draw everything in a big loop */
1634 	draw_parts &= (PART_FRAME | PART_HANDLES);
1635 	draw_handles = (draw_parts & PART_HANDLES);
1636 
1637 	for (part = PART_BORDER_N; (part & PART_FRAME); part <<= 1)
1638 	{
1639 		if (part & draw_parts)
1640 		{
1641 			border_draw_one_border_part(
1642 				cd, fw, &br->sidebar_g, frame_g, br, part,
1643 				draw_handles,
1644 				(pressed_parts & part) ? True : False,
1645 				do_clear);
1646 		}
1647 	}
1648 
1649 	return;
1650 }
1651 
1652 /*
1653  *
1654  *  Draws a little pattern within a window (more complex)
1655  *
1656  */
border_draw_vector_to_pixmap(Pixmap dest_pix,common_decorations_type * cd,int is_toggled,struct vector_coords * coords,rectangle * pixmap_g)1657 static void border_draw_vector_to_pixmap(
1658 	Pixmap dest_pix, common_decorations_type *cd, int is_toggled,
1659 	struct vector_coords *coords, rectangle *pixmap_g)
1660 {
1661 	GC gcs[4];
1662 	int i;
1663 
1664 	if (coords->use_fgbg == 1)
1665 	{
1666 		Globalgcv.foreground = cd->fore_color;
1667 		Globalgcm = GCForeground;
1668 		XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
1669 		Globalgcv.foreground = cd->back_color;
1670 		XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
1671 		gcs[3] = Scr.ScratchGC3; /* @3 is fg */
1672 		gcs[2] = Scr.ScratchGC4; /* @2 is bg */
1673 	}
1674 	if (is_toggled)
1675 	{
1676 		gcs[0] = cd->relief_gc;
1677 		gcs[1] = cd->shadow_gc;
1678 	}
1679 	else
1680 	{
1681 		gcs[0] = cd->shadow_gc;
1682 		gcs[1] = cd->relief_gc;
1683 	}
1684 	for (i = 1; i < coords->num; i++)
1685 	{
1686 		if (coords->c[i] < 0 || coords->c[i] >= 4)
1687 		{
1688 			/* don't draw a line */
1689 			continue;
1690 		}
1691 		XDrawLine(
1692 			dpy, dest_pix, gcs[coords->c[i]],
1693 			pixmap_g->width * coords->x[i-1] / 100 +
1694 			coords->xoff[i-1],
1695 			pixmap_g->height * coords->y[i-1] / 100 +
1696 			coords->yoff[i-1],
1697 			pixmap_g->width * coords->x[i] / 100 +
1698 			coords->xoff[i],
1699 			pixmap_g->height * coords->y[i] / 100 +
1700 			coords->yoff[i]);
1701 	}
1702 
1703 	return;
1704 }
1705 
1706 /*
1707  *
1708  *  Handle Title pixmaps used for UseTitleStyle
1709  *
1710  */
border_setup_bar_pixmaps(titlebar_descr * td,dynamic_common_decorations * dcd,DecorFace * df,ButtonState bs)1711 static void border_setup_bar_pixmaps(
1712 	titlebar_descr *td, dynamic_common_decorations *dcd, DecorFace *df,
1713 	ButtonState bs)
1714 {
1715 	int count = dcd->bar_pixmaps[bs].count;
1716 	DecorFace *tsdf;
1717 	int i, j, mp_part_left, mp_part_right;
1718 
1719 	if (count != 0)
1720 	{
1721 		/* ok */
1722 		return;
1723 	}
1724 
1725 	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
1726 	{
1727 		if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
1728 		{
1729 			count++;
1730 		}
1731 		else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
1732 		{
1733 			border_mp_get_use_title_style_parts_and_geometry(
1734 				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1735 				tsdf->u.mp.solid_flags, True, NULL,
1736 				&mp_part_left);
1737 			border_mp_get_use_title_style_parts_and_geometry(
1738 				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1739 				tsdf->u.mp.solid_flags, False, NULL,
1740 				&mp_part_right);
1741 			for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
1742 			{
1743 				if (j != mp_part_left && j != mp_part_right)
1744 				{
1745 					continue;
1746 				}
1747 				if (tsdf->u.mp.acs[j].cs >= 0 ||
1748 				    tsdf->u.mp.pixmaps[j])
1749 				{
1750 					count++;
1751 				}
1752 			}
1753 		}
1754 	}
1755 	if (count == 0)
1756 	{
1757 		dcd->bar_pixmaps[bs].count = -1;
1758 		return;
1759 	}
1760 	else
1761 	{
1762 		dcd->bar_pixmaps[bs].bps = fxmalloc(count * sizeof(bar_pixmap));
1763 	}
1764 	dcd->bar_pixmaps[bs].count = count;
1765 	i = 0;
1766 	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
1767 	{
1768 		if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
1769 		{
1770 			dcd->bar_pixmaps[bs].bps[i].p = None;
1771 			dcd->bar_pixmaps[bs].bps[i].mp_created_pic = NULL;
1772 			dcd->bar_pixmaps[bs].bps[i].cs = tsdf->u.acs.cs;
1773 			dcd->bar_pixmaps[bs].bps[i].mp_pic = NULL;
1774 			dcd->bar_pixmaps[bs].bps[i].created = 0;
1775 			dcd->bar_pixmaps[bs].bps[i].mp_part = TBMP_NONE;
1776 			i++;
1777 		}
1778 		else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
1779 		{
1780 			border_mp_get_use_title_style_parts_and_geometry(
1781 				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1782 				tsdf->u.mp.solid_flags, True, NULL,
1783 				&mp_part_left);
1784 			border_mp_get_use_title_style_parts_and_geometry(
1785 				td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1786 				tsdf->u.mp.solid_flags, False, NULL,
1787 				&mp_part_right);
1788 			for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
1789 			{
1790 				if (j != mp_part_left && j != mp_part_right)
1791 				{
1792 					continue;
1793 				}
1794 				if (tsdf->u.mp.acs[j].cs >= 0 ||
1795 				    tsdf->u.mp.pixmaps[j])
1796 				{
1797 					dcd->bar_pixmaps[bs].bps[i].p = None;
1798 					dcd->bar_pixmaps[bs].bps[i].
1799 						mp_created_pic = NULL;
1800 					dcd->bar_pixmaps[bs].bps[i].cs =
1801 						tsdf->u.mp.acs[j].cs;
1802 					dcd->bar_pixmaps[bs].bps[i].mp_pic =
1803 						tsdf->u.mp.pixmaps[j];
1804 					dcd->bar_pixmaps[bs].bps[i].created = 0;
1805 					dcd->bar_pixmaps[bs].bps[i].mp_part = j;
1806 					i++;
1807 				}
1808 			}
1809 		}
1810 	}
1811 }
1812 
border_get_bar_pixmaps(dynamic_common_decorations * dcd,rectangle * bar_g,ButtonState bs,int cset,FvwmPicture * mp_pic,int mp_part,int stretch,FvwmPicture ** mp_ret_pic)1813 static Pixmap border_get_bar_pixmaps(
1814 	dynamic_common_decorations *dcd, rectangle *bar_g, ButtonState bs,
1815 	int cset, FvwmPicture *mp_pic, int mp_part, int stretch,
1816 	FvwmPicture **mp_ret_pic)
1817 {
1818 	ButtonState b;
1819 	int i,j;
1820 	int count = dcd->bar_pixmaps[bs].count;
1821 
1822 	if (count <= 0)
1823 	{
1824 		return None;
1825 	}
1826 
1827 	i = 0;
1828 	while(i < count &&
1829 	(dcd->bar_pixmaps[bs].bps[i].cs != cset ||
1830 	      dcd->bar_pixmaps[bs].bps[i].mp_part != mp_part ||
1831 	      dcd->bar_pixmaps[bs].bps[i].mp_pic != mp_pic))
1832 	{
1833 		i++;
1834 	}
1835 	if (i == count)
1836 	{
1837 		return None;
1838 	}
1839 	if (mp_ret_pic)
1840 	{
1841 		*mp_ret_pic = dcd->bar_pixmaps[bs].bps[i].mp_created_pic;
1842 	}
1843 	if (dcd->bar_pixmaps[bs].bps[i].p == None)
1844 	{
1845 		/* see if we have it */
1846 		b = 0;
1847 		while (b < BS_MaxButtonState)
1848 		{
1849 			int c = dcd->bar_pixmaps[b].count;
1850 			j = 0;
1851 			while(j < c &&
1852 			      (dcd->bar_pixmaps[b].bps[j].cs != cset ||
1853 			       dcd->bar_pixmaps[b].bps[j].mp_part != mp_part ||
1854 			       dcd->bar_pixmaps[b].bps[j].mp_pic != mp_pic))
1855 			{
1856 				j++;
1857 			}
1858 			if (j < c && dcd->bar_pixmaps[b].bps[j].p)
1859 			{
1860 				dcd->bar_pixmaps[bs].bps[i].p =
1861 					dcd->bar_pixmaps[b].bps[j].p;
1862 				if (mp_pic && mp_ret_pic)
1863 				{
1864 					*mp_ret_pic =
1865 						dcd->bar_pixmaps[bs].bps[i].
1866 						mp_created_pic =
1867 						dcd->bar_pixmaps[b].bps[j].
1868 						mp_created_pic;
1869 				}
1870 				break;
1871 			}
1872 			b++;
1873 		}
1874 	}
1875 	if (dcd->bar_pixmaps[bs].bps[i].p == None)
1876 	{
1877 		if (cset >= 0)
1878 		{
1879 			dcd->bar_pixmaps[bs].bps[i].p = CreateBackgroundPixmap(
1880 				dpy, Scr.NoFocusWin, bar_g->width, bar_g->height,
1881 				&Colorset[cset], Pdepth, Scr.BordersGC, False);
1882 			dcd->bar_pixmaps[bs].bps[i].created = True;
1883 		}
1884 		else if (mp_pic && mp_ret_pic)
1885 		{
1886 			if (stretch)
1887 			{
1888 				dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
1889 					PGraphicsCreateStretchPicture(
1890 						dpy, Scr.NoFocusWin, mp_pic,
1891 						bar_g->width, bar_g->height,
1892 						Scr.BordersGC, Scr.MonoGC,
1893 						Scr.AlphaGC);
1894 			}
1895 			else
1896 			{
1897 				dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
1898 					PGraphicsCreateTiledPicture(
1899 						dpy, Scr.NoFocusWin, mp_pic,
1900 						bar_g->width, bar_g->height,
1901 						Scr.BordersGC, Scr.MonoGC,
1902 						Scr.AlphaGC);
1903 			}
1904 			if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic)
1905 			{
1906 				dcd->bar_pixmaps[bs].bps[i].created = True;
1907 				*mp_ret_pic =
1908 					dcd->bar_pixmaps[bs].bps[i].
1909 					mp_created_pic;
1910 				dcd->bar_pixmaps[bs].bps[i].p =
1911 					dcd->bar_pixmaps[bs].bps[i].
1912 					mp_created_pic->picture;
1913 			}
1914 		}
1915 	}
1916 	return dcd->bar_pixmaps[bs].bps[i].p;
1917 }
1918 
border_free_bar_pixmaps(dynamic_common_decorations * dcd)1919 static void border_free_bar_pixmaps(
1920 	dynamic_common_decorations *dcd)
1921 {
1922 	ButtonState bs;
1923 	int i;
1924 
1925 	for (bs = 0; bs < BS_MaxButtonState; bs++)
1926 	{
1927 		if (dcd->bar_pixmaps[bs].count < 1)
1928 		{
1929 			continue;
1930 		}
1931 		for (i = 0; i < dcd->bar_pixmaps[bs].count; i++)
1932 		{
1933 			if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic &&
1934 			    dcd->bar_pixmaps[bs].bps[i].created)
1935 			{
1936 				PDestroyFvwmPicture(
1937 					dpy,
1938 					dcd->bar_pixmaps[bs].bps[i].
1939 					mp_created_pic);
1940 			}
1941 			else if (dcd->bar_pixmaps[bs].bps[i].p != None &&
1942 				 dcd->bar_pixmaps[bs].bps[i].created)
1943 			{
1944 				XFreePixmap(
1945 					dpy, dcd->bar_pixmaps[bs].bps[i].p);
1946 			}
1947 		}
1948 		free(dcd->bar_pixmaps[bs].bps);
1949 	}
1950 }
1951 
1952 /*
1953  *
1954  *  MultiPixmap (aka, fancy title bar) (tril@igs.net)
1955  *
1956  */
1957 #define TBMP_HAS_PART(p, pm, acs, sf) \
1958        (pm[p] || acs[p].cs >= 0 || (sf & (1 << p)))
1959 
1960 /*  Tile or stretch src into dest, starting at the given location and
1961  *  continuing for the given width and height. This is a utility function used
1962  *  by border_mp_draw_mp_titlebar. (tril@igs.net) */
border_mp_render_into_pixmap(titlebar_descr * td,common_decorations_type * cd,FvwmPicture ** src,FvwmAcs * acs,Pixel * pixels,unsigned short solid_flags,unsigned short stretch_flags,int part,Pixmap dest,Window w,rectangle * full_g,rectangle * title_g,ButtonState bs,rectangle * g)1963 static void border_mp_render_into_pixmap(
1964 	titlebar_descr *td, common_decorations_type *cd, FvwmPicture **src,
1965 	FvwmAcs *acs, Pixel *pixels, unsigned short solid_flags,
1966 	unsigned short stretch_flags, int part, Pixmap dest, Window w,
1967 	rectangle *full_g, rectangle *title_g, ButtonState bs, rectangle *g)
1968 {
1969 	int x = 0;
1970 	int y = 0;
1971 	pixmap_background_type bg;
1972 	rectangle dest_g;
1973 	dynamic_common_decorations *dcd;
1974 
1975 	dcd = &cd->dynamic_cd;
1976 	/* setup some default */
1977 	bg.pixmap.fra.mask = 0;
1978 	bg.pixmap.flags.is_stretched = 0;
1979 	bg.pixmap.flags.is_tiled = 0;
1980 	bg.flags.use_pixmap = 1;
1981 	bg.pixmap.p = bg.pixmap.alpha = bg.pixmap.shape = None;
1982 	bg.pixmap.g.x = 0;
1983 	bg.pixmap.g.y = 0;
1984 	dest_g.width = g->width + g->x;
1985 	dest_g.height = g->height + g->y;
1986 	dest_g.x = g->x;
1987 	dest_g.y = g->y;
1988 
1989 	if (solid_flags & (1 << part))
1990 	{
1991 		bg.flags.use_pixmap = 0;
1992 		bg.pixel = pixels[part];
1993 		border_fill_pixmap_background(dest, &dest_g, &bg, cd);
1994 		return;
1995 	}
1996 	else if (acs[part].cs >= 0)
1997 	{
1998 		Pixmap p = None;
1999 
2000 		bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
2001 		bg.pixmap.fra.added_alpha_percent = acs[part].alpha_percent;
2002 		if (CSET_IS_TRANSPARENT_PR(acs[part].cs))
2003 		{
2004 			return;
2005 		}
2006 		if (CSET_IS_TRANSPARENT_ROOT(acs[part].cs))
2007 		{
2008 			p = border_create_root_transparent_pixmap(
2009 				td, w, g->width + g->x, g->height + g->y,
2010 				acs[part].cs);
2011 			bg.pixmap.p = p;
2012 			bg.pixmap.depth = Pdepth;
2013 			bg.pixmap.g.width = g->width;
2014 			bg.pixmap.g.height = g->height;
2015 			bg.pixmap.g.x = g->x;
2016 			bg.pixmap.g.y = g->y;
2017 		}
2018 		else if (full_g != NULL)
2019 		{
2020 			bg.pixmap.p = border_get_bar_pixmaps(
2021 				dcd, full_g, bs, acs[part].cs, NULL, part,
2022 				(stretch_flags & (1 << part)), NULL);
2023 			if (bg.pixmap.p)
2024 			{
2025 				if (part != TBMP_RIGHT_MAIN)
2026 				{
2027 					/* left buttons offset */
2028 					x = title_g->x - full_g->x;
2029 					y = title_g->y - full_g->y;
2030 				}
2031 				bg.pixmap.g.width = full_g->width;
2032 				bg.pixmap.g.height = full_g->height;
2033 				bg.pixmap.flags.is_tiled = 1;
2034 				bg.pixmap.g.x = x;
2035 				bg.pixmap.g.y = y;
2036 				bg.pixmap.depth = Pdepth;
2037 			}
2038 		}
2039 		if (!bg.pixmap.p)
2040 		{
2041 			int bg_w, bg_h;
2042 
2043 			p = CreateBackgroundPixmap(
2044 				dpy, w, g->width, g->height,
2045 				&Colorset[acs[part].cs], Pdepth, Scr.BordersGC,
2046 				False);
2047 			bg.pixmap.p = p;
2048 			GetWindowBackgroundPixmapSize(
2049 				&Colorset[acs[part].cs], g->width, g->height,
2050 				&bg_w, &bg_h);
2051 			bg.pixmap.g.width = bg_w;
2052 			bg.pixmap.g.height = bg_h;
2053 			bg.pixmap.depth = Pdepth;
2054 			bg.pixmap.flags.is_tiled = 1;
2055 		}
2056 		if (bg.pixmap.p)
2057 		{
2058 			border_fill_pixmap_background(dest, &dest_g, &bg, cd);
2059 		}
2060 		if (p)
2061 		{
2062 			XFreePixmap(dpy, p);
2063 		}
2064 	}
2065 	else if (src[part])
2066 	{
2067 		FvwmPicture *full_pic = NULL;
2068 		Pixmap p;
2069 
2070 		if (full_g != NULL)
2071 		{
2072 			p = border_get_bar_pixmaps(
2073 				dcd, full_g, bs, -1, src[part], part,
2074 				(stretch_flags & (1 << part)), &full_pic);
2075 			if (p && full_pic)
2076 			{
2077 				if (part != TBMP_RIGHT_MAIN)
2078 				{
2079 					/* left buttons offset */
2080 					x = title_g->x - full_g->x;
2081 					y = title_g->y - full_g->y;
2082 				}
2083 				bg.pixmap.p = full_pic->picture;
2084 				bg.pixmap.shape = full_pic->mask;
2085 				bg.pixmap.alpha = full_pic->alpha;
2086 				bg.pixmap.depth = full_pic->depth;
2087 				bg.pixmap.g.width = full_pic->width;
2088 				bg.pixmap.g.height = full_pic->height;
2089 				bg.pixmap.g.x = x;
2090 				bg.pixmap.g.y = y;
2091 			}
2092 		}
2093 		if (!bg.pixmap.p)
2094 		{
2095 			if (stretch_flags & (1 << part))
2096 			{
2097 				bg.pixmap.flags.is_stretched = 1;
2098 			}
2099 			else
2100 			{
2101 				bg.pixmap.flags.is_tiled = 1;
2102 			}
2103 			bg.pixmap.p = src[part]->picture;
2104 			bg.pixmap.shape = src[part]->mask;
2105 			bg.pixmap.alpha = src[part]->alpha;
2106 			bg.pixmap.depth = src[part]->depth;
2107 			bg.pixmap.g.width = src[part]->width;
2108 			bg.pixmap.g.height = src[part]->height;
2109 			bg.pixmap.stretch_w = dest_g.width - dest_g.x;
2110 			bg.pixmap.stretch_h = dest_g.height - dest_g.y;
2111 
2112 		}
2113 		if (bg.pixmap.p)
2114 		{
2115 			border_fill_pixmap_background(dest, &dest_g, &bg, cd);
2116 		}
2117 	}
2118 
2119 	return;
2120 }
2121 
border_mp_get_length(titlebar_descr * td,FvwmPicture ** pm,FvwmAcs * acs,unsigned int solid_flags,int part)2122 static int border_mp_get_length(
2123 	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
2124 	unsigned int solid_flags, int part)
2125 {
2126 	if (acs[part].cs >= 0 || (solid_flags & (1 << part)))
2127 	{
2128 		/* arbitrary */
2129 		if (td->has_vt)
2130 		{
2131 			return td->bar_g.width/2;
2132 		}
2133 		else
2134 		{
2135 			return td->bar_g.height/2;
2136 		}
2137 	}
2138 	if (pm[part] == NULL)
2139 	{
2140 		return 0;
2141 	}
2142 	else if (td->has_vt)
2143 	{
2144 		return pm[part]->height;
2145 	}
2146 	else
2147 	{
2148 		return pm[part]->width;
2149 	}
2150 }
2151 
2152 /* geometries relatively to the frame */
border_mp_get_titlebar_descr(FvwmWindow * fw,titlebar_descr * td,DecorFace * df)2153 static void border_mp_get_titlebar_descr(
2154 	FvwmWindow *fw, titlebar_descr *td, DecorFace *df)
2155 {
2156 	DecorFace *tsdf;
2157 	FvwmPicture **pm;
2158 	FvwmAcs *acs;
2159 	int add,tmpi;
2160 	int left_of_text = 0;
2161 	int right_of_text = 0;
2162 	int left_end = 0;
2163 	int right_end = 0;
2164 	int before_space, after_space, under_offset, under_width;
2165 	Bool has_mp = False;
2166 	JustificationType just;
2167 	unsigned short sf;
2168 	int is_start = 0;
2169 
2170 	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
2171 	/* first compute under text width */
2172 	if (td->length > 0)
2173 	{
2174 		under_width = td->length + 2*TBMP_TITLE_PADDING;
2175 	}
2176 	else
2177 	{
2178 		under_width = 0;
2179 	}
2180 	if (under_width > fw->title_length)
2181 	{
2182 		under_width = fw->title_length;
2183 		td->offset = (fw->title_length - td->length) / 2;
2184 		just = JUST_CENTER;
2185 	}
2186 	for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
2187 	{
2188 		if (tsdf->style.face_type != MultiPixmap)
2189 		{
2190 			continue;
2191 		}
2192 		has_mp = True;
2193 		acs = tsdf->u.mp.acs;
2194 		pm = tsdf->u.mp.pixmaps;
2195 		sf = tsdf->u.mp.solid_flags;
2196 		add = border_mp_get_length(
2197 			td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
2198 		if (add > left_of_text &&
2199 		    add + left_end + right_of_text + right_end + under_width +
2200 		    2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2201 		{
2202 			left_of_text = add;
2203 		}
2204 		add = border_mp_get_length(
2205 			td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
2206 		if (add > right_of_text &&
2207 		    add + left_end + left_of_text + right_end + under_width +
2208 		    2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2209 		{
2210 			right_of_text = add;
2211 		}
2212 		add = border_mp_get_length(
2213 			td, pm, acs, sf, TBMP_LEFT_END);
2214 		if (add > left_end &&
2215 		    add + right_of_text + left_of_text + right_end +
2216 		    under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2217 		{
2218 			left_end = add;
2219 		}
2220 		add = border_mp_get_length(
2221 			td, pm, acs, sf, TBMP_RIGHT_END);
2222 		if (add > right_end &&
2223 		    add + right_of_text + left_of_text + left_end +
2224 		    under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2225 		{
2226 			right_end = add;
2227 		}
2228 	}
2229 
2230 	if (!has_mp)
2231 	{
2232 		return;
2233 	}
2234 
2235 	switch (just)
2236 	{
2237 	case JUST_LEFT:
2238 		is_start = 1;
2239 		/* fall through */
2240 	case JUST_RIGHT:
2241 		if (td->has_an_upsidedown_rotation)
2242 		{
2243 			is_start = !is_start;
2244 		}
2245 		if (is_start)
2246 		{
2247 			if (td->has_an_upsidedown_rotation)
2248 			{
2249 				td->offset = max(
2250 					td->offset, right_of_text + right_end +
2251 					TBMP_MIN_RL_TITLE_LENGTH +
2252 					TBMP_TITLE_PADDING);
2253 			}
2254 			else
2255 			{
2256 				td->offset = max(
2257 					td->offset, left_of_text + left_end +
2258 					TBMP_MIN_RL_TITLE_LENGTH +
2259 					TBMP_TITLE_PADDING);
2260 			}
2261 		}
2262 		else
2263 		{
2264 			if (td->has_an_upsidedown_rotation)
2265 			{
2266 				td->offset = min(
2267 					td->offset, fw->title_length -
2268 					(td->length + left_of_text +
2269 					 left_end + TBMP_MIN_RL_TITLE_LENGTH +
2270 					 TBMP_TITLE_PADDING));
2271 			}
2272 			else
2273 			{
2274 				td->offset = min(
2275 					td->offset, fw->title_length -
2276 					(td->length + right_of_text +
2277 					 right_end + TBMP_MIN_RL_TITLE_LENGTH +
2278 					 TBMP_TITLE_PADDING));
2279 			}
2280 		}
2281 		break;
2282 	case JUST_CENTER:
2283 	default:
2284 		break;
2285 	}
2286 
2287 	under_offset = td->offset - (under_width - td->length)/2;
2288 	before_space = under_offset;
2289 	if (td->has_vt)
2290 	{
2291 		after_space =
2292 			td->layout.title_g.height - before_space - under_width;
2293 	}
2294 	else
2295 	{
2296 		after_space =
2297 			td->layout.title_g.width - before_space - under_width;
2298 	}
2299 	if (td->has_an_upsidedown_rotation)
2300 	{
2301 		td->left_end_length = right_end;
2302 		td->left_of_text_length = right_of_text;
2303 		td->right_of_text_length = left_of_text;
2304 		td->right_end_length = left_end;
2305 		tmpi = before_space;
2306 		before_space = after_space;
2307 		after_space = tmpi;
2308 	}
2309 	else
2310 	{
2311 		td->left_end_length = left_end;
2312 		td->left_of_text_length = left_of_text;
2313 		td->right_of_text_length = right_of_text;
2314 		td->right_end_length = right_end;
2315 	}
2316 
2317 	if (td->has_vt)
2318 	{
2319 		td->under_text_g.width = td->bar_g.width;
2320 		td->under_text_g.height = under_width;
2321 		td->under_text_g.x = 0;
2322 		td->under_text_g.y = under_offset;
2323 	}
2324 	else
2325 	{
2326 		td->under_text_g.height = td->bar_g.height;
2327 		td->under_text_g.width = under_width;
2328 		td->under_text_g.x = under_offset;
2329 		td->under_text_g.y = 0;
2330 	}
2331 
2332 	/* width & height */
2333 	if (td->has_vt)
2334 	{
2335 		/* left */
2336 		td->full_left_main_g.width = td->bar_g.width;
2337 		td->full_left_main_g.height =
2338 			before_space + td->left_buttons_g.height;
2339 		td->left_main_g.width = td->bar_g.width;
2340 		td->left_main_g.height = before_space;
2341 		/* right */
2342 		td->full_right_main_g.width = td->bar_g.width;
2343 		td->full_right_main_g.height = after_space +
2344 			td->right_buttons_g.height;
2345 		td->right_main_g.width = td->bar_g.width;
2346 		td->right_main_g.height = after_space;
2347 	}
2348 	else
2349 	{
2350 		/* left */
2351 		td->full_left_main_g.height = td->bar_g.height;
2352 		td->full_left_main_g.width =
2353 			before_space + td->left_buttons_g.width;
2354 		td->left_main_g.height = td->bar_g.height;
2355 		td->left_main_g.width = before_space;
2356 		/* right */
2357 		td->full_right_main_g.height = td->bar_g.height;
2358 		td->full_right_main_g.width = after_space +
2359 			td->right_buttons_g.width;
2360 		td->right_main_g.height = td->bar_g.height;
2361 		td->right_main_g.width = after_space;
2362 	}
2363 
2364 	/* position */
2365 	if (td->has_an_upsidedown_rotation)
2366 	{
2367 		td->full_right_main_g.x = td->bar_g.x;
2368 		td->full_right_main_g.y = td->bar_g.y;
2369 		td->right_main_g.x = 0;
2370 		td->right_main_g.y = 0;
2371 	}
2372 	else
2373 	{
2374 		td->full_left_main_g.x = td->bar_g.x;
2375 		td->full_left_main_g.y = td->bar_g.y;
2376 		td->left_main_g.x = 0;
2377 		td->left_main_g.y = 0;
2378 	}
2379 
2380 	if (td->has_vt)
2381 	{
2382 		if (td->has_an_upsidedown_rotation)
2383 		{
2384 			td->full_left_main_g.x = td->bar_g.x;
2385 			td->full_left_main_g.y =
2386 				td->full_right_main_g.height + td->bar_g.y +
2387 				td->under_text_g.height;
2388 			td->left_main_g.y =
2389 				td->under_text_g.y + td->under_text_g.height;
2390 			td->left_main_g.x = 0;
2391 		}
2392 		else
2393 		{
2394 			td->full_right_main_g.x = td->bar_g.x;
2395 			td->full_right_main_g.y =
2396 				td->full_left_main_g.height + td->bar_g.y +
2397 				td->under_text_g.height;
2398 			td->right_main_g.y =
2399 				td->under_text_g.y + td->under_text_g.height;
2400 			td->right_main_g.x = 0;
2401 		}
2402 	}
2403 	else
2404 	{
2405 		if (td->has_an_upsidedown_rotation)
2406 		{
2407 			td->full_left_main_g.x =
2408 				td->full_right_main_g.width + td->bar_g.x +
2409 				td->under_text_g.width;
2410 			td->full_left_main_g.y = td->bar_g.y;
2411 			td->left_main_g.x =
2412 				td->under_text_g.x + td->under_text_g.width;
2413 			td->left_main_g.y = 0;
2414 		}
2415 		else
2416 		{
2417 			td->full_right_main_g.x =
2418 				td->full_left_main_g.width + td->bar_g.x +
2419 				td->under_text_g.width;
2420 			td->full_right_main_g.y = td->bar_g.y;
2421 			td->right_main_g.x =
2422 				td->under_text_g.x + td->under_text_g.width;
2423 			td->right_main_g.y = 0;
2424 		}
2425 	}
2426 }
2427 
2428 /* the returned geometries are relative to the titlebar (not the frame) */
border_mp_get_extreme_geometry(titlebar_descr * td,FvwmPicture ** pm,FvwmAcs * acs,unsigned short sf,rectangle * left_of_text_g,rectangle * right_of_text_g,rectangle * left_end_g,rectangle * right_end_g)2429 static void border_mp_get_extreme_geometry(
2430 	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs, unsigned short sf,
2431 	rectangle *left_of_text_g, rectangle *right_of_text_g,
2432 	rectangle *left_end_g, rectangle *right_end_g)
2433 {
2434 	int left_of_text = 0;
2435 	int right_of_text = 0;
2436 	int left_end = 0;
2437 	int right_end = 0;
2438 
2439 	left_of_text = border_mp_get_length(
2440 		td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
2441 	left_end = border_mp_get_length(
2442 		td, pm, acs, sf, TBMP_LEFT_END);
2443 	right_of_text = border_mp_get_length(
2444 		td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
2445 	right_end = border_mp_get_length(
2446 			td, pm, acs, sf, TBMP_RIGHT_END);
2447 
2448 	if (left_of_text > 0 && left_of_text <= td->left_of_text_length)
2449 	{
2450 		if (td->has_vt)
2451 		{
2452 			left_of_text_g->y = td->under_text_g.y - left_of_text;
2453 			left_of_text_g->x = 0;
2454 			left_of_text_g->height = left_of_text;
2455 			left_of_text_g->width = td->bar_g.width;
2456 		}
2457 		else
2458 		{
2459 			left_of_text_g->x = td->under_text_g.x - left_of_text;
2460 			left_of_text_g->y = 0;
2461 			left_of_text_g->width = left_of_text;
2462 			left_of_text_g->height = td->bar_g.height;
2463 		}
2464 	}
2465 	else
2466 	{
2467 		left_of_text_g->x = 0;
2468 		left_of_text_g->y = 0;
2469 		left_of_text_g->width = 0;
2470 		left_of_text_g->height = 0;
2471 	}
2472 
2473 	if (right_of_text > 0 && right_of_text <= td->right_of_text_length)
2474 	{
2475 		if (td->has_vt)
2476 		{
2477 			right_of_text_g->y =
2478 				td->under_text_g.y + td->under_text_g.height;
2479 			right_of_text_g->x = 0;
2480 			right_of_text_g->height = right_of_text;
2481 			right_of_text_g->width = td->bar_g.width;
2482 		}
2483 		else
2484 		{
2485 			right_of_text_g->x =
2486 				td->under_text_g.x + td->under_text_g.width;
2487 			right_of_text_g->y = 0;
2488 			right_of_text_g->width = right_of_text;
2489 			right_of_text_g->height = td->bar_g.height;
2490 		}
2491 	}
2492 	else
2493 	{
2494 		right_of_text_g->x = 0;
2495 		right_of_text_g->y = 0;
2496 		right_of_text_g->width = 0;
2497 		right_of_text_g->height = 0;
2498 	}
2499 
2500 	if (left_end > 0 && left_end <= td->left_end_length)
2501 	{
2502 		if (td->has_vt)
2503 		{
2504 			left_end_g->y = 0;
2505 			left_end_g->x = 0;
2506 			left_end_g->height = left_end;
2507 			left_end_g->width = td->bar_g.width;
2508 		}
2509 		else
2510 		{
2511 			left_end_g->x = 0;
2512 			left_end_g->y = 0;
2513 			left_end_g->width = left_end;
2514 			left_end_g->height = td->bar_g.height;
2515 		}
2516 	}
2517 	else
2518 	{
2519 		left_end_g->x = 0;
2520 		left_end_g->y = 0;
2521 		left_end_g->width = 0;
2522 		left_end_g->height = 0;
2523 	}
2524 
2525 	if (right_end > 0 && right_end <= td->right_end_length)
2526 	{
2527 		if (td->has_vt)
2528 		{
2529 			right_end_g->y =
2530 				td->layout.title_g.height - right_end;
2531 			right_end_g->x = 0;
2532 			right_end_g->height = right_end;
2533 			right_end_g->width = td->bar_g.width;
2534 		}
2535 		else
2536 		{
2537 			right_end_g->x =
2538 				td->layout.title_g.width - right_end;
2539 			right_end_g->y = 0;
2540 			right_end_g->width = right_end;
2541 			right_end_g->height = td->bar_g.height;
2542 		}
2543 	}
2544 	else
2545 	{
2546 		right_end_g->x = 0;
2547 		right_end_g->y = 0;
2548 		right_end_g->width = 0;
2549 		right_end_g->height = 0;
2550 	}
2551 
2552 	return;
2553 }
2554 
border_mp_get_use_title_style_parts_and_geometry(titlebar_descr * td,FvwmPicture ** pm,FvwmAcs * acs,unsigned short sf,int is_left,rectangle * g,int * part)2555 static Bool border_mp_get_use_title_style_parts_and_geometry(
2556 	titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
2557 	unsigned short sf, int is_left, rectangle *g, int *part)
2558 {
2559 	rectangle *tmp_g = NULL;
2560 	Bool g_ok = True;
2561 
2562 	if (is_left && TBMP_HAS_PART(TBMP_LEFT_BUTTONS, pm, acs, sf))
2563 	{
2564 		*part = TBMP_LEFT_BUTTONS;
2565 		tmp_g = &td->left_buttons_g;
2566 	}
2567 	else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_BUTTONS, pm, acs, sf))
2568 	{
2569 		*part = TBMP_RIGHT_BUTTONS;
2570 		tmp_g = &td->right_buttons_g;
2571 	}
2572 	else if (is_left && TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, sf))
2573 	{
2574 		*part = TBMP_LEFT_MAIN;
2575 		tmp_g = &td->full_left_main_g;
2576 	}
2577 	else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, sf))
2578 	{
2579 		*part = TBMP_RIGHT_MAIN;
2580 		tmp_g = &td->full_right_main_g;
2581 	}
2582 	else if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, sf))
2583 	{
2584 		*part = TBMP_MAIN;
2585 		tmp_g = &(td->bar_g);
2586 	}
2587 	else
2588 	{
2589 		*part = TBMP_NONE;
2590 	}
2591 	if (g && tmp_g)
2592 	{
2593 		g->x = tmp_g->x;
2594 		g->y = tmp_g->y;
2595 		g->width = tmp_g->width;
2596 		g->height = tmp_g->height;
2597 		g_ok = True;
2598 	}
2599 
2600 	return g_ok;
2601 }
2602 
2603 /*  Redraws multi-pixmap titlebar (tril@igs.net) */
border_mp_draw_mp_titlebar(FvwmWindow * fw,titlebar_descr * td,DecorFace * df,Pixmap dest_pix,Window w)2604 static void border_mp_draw_mp_titlebar(
2605 	FvwmWindow *fw, titlebar_descr *td, DecorFace *df, Pixmap dest_pix,
2606 	Window w)
2607 {
2608 	FvwmPicture **pm;
2609 	FvwmAcs *acs;
2610 	Pixel *pixels;
2611 	unsigned short solid_flags;
2612 	unsigned short stretch_flags;
2613 	rectangle tmp_g, left_of_text_g,left_end_g,right_of_text_g,right_end_g;
2614 	ButtonState bs;
2615 
2616 	bs = td->tbstate.tstate;
2617 	pm = df->u.mp.pixmaps;
2618 	acs = df->u.mp.acs;
2619 	pixels = df->u.mp.pixels;
2620 	stretch_flags = df->u.mp.stretch_flags;
2621 	solid_flags = df->u.mp.solid_flags;
2622 	tmp_g.x = 0;
2623 	tmp_g.y = 0;
2624 	tmp_g.width = td->layout.title_g.width;
2625 	tmp_g.height = td->layout.title_g.height;
2626 
2627 	if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, solid_flags))
2628 	{
2629 		border_mp_render_into_pixmap(
2630 			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2631 			TBMP_MAIN, dest_pix, w, &td->bar_g, &td->layout.title_g,
2632 			bs, &tmp_g);
2633 	}
2634 	else if (td->length <= 0)
2635 	{
2636 		border_mp_render_into_pixmap(
2637 			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2638 			TBMP_LEFT_MAIN, dest_pix, w, NULL, &td->layout.title_g,
2639 			bs, &tmp_g);
2640 	}
2641 
2642 	border_mp_get_extreme_geometry(
2643 		td, pm, acs, solid_flags, &left_of_text_g, &right_of_text_g,
2644 		&left_end_g, &right_end_g);
2645 
2646 	if (td->length > 0)
2647 	{
2648 		if (TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, solid_flags) &&
2649 		    td->left_main_g.width > 0 && td->left_main_g.height > 0)
2650 		{
2651 			border_mp_render_into_pixmap(
2652 				td, td->cd, pm, acs, pixels, solid_flags,
2653 				stretch_flags, TBMP_LEFT_MAIN, dest_pix, w,
2654 				&td->full_left_main_g, &td->layout.title_g, bs,
2655 				&td->left_main_g);
2656 		}
2657 		if (TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, solid_flags) &&
2658 		    td->right_main_g.width > 0 && td->right_main_g.height > 0)
2659 		{
2660 			border_mp_render_into_pixmap(
2661 				td, td->cd, pm, acs, pixels, solid_flags,
2662 				stretch_flags, TBMP_RIGHT_MAIN, dest_pix, w,
2663 				&td->full_right_main_g, &td->layout.title_g, bs,
2664 				&td->right_main_g);
2665 		}
2666 		if (TBMP_HAS_PART(TBMP_UNDER_TEXT, pm, acs, solid_flags)  &&
2667 		    td->under_text_g.width > 0 && td->under_text_g.height > 0)
2668 		{
2669 			border_mp_render_into_pixmap(
2670 				td, td->cd, pm, acs, pixels, solid_flags,
2671 				stretch_flags, TBMP_UNDER_TEXT, dest_pix, w,
2672 				NULL, &td->layout.title_g, bs,
2673 				&td->under_text_g);
2674 		}
2675 		if (left_of_text_g.width > 0 && left_of_text_g.height > 0)
2676 		{
2677 			border_mp_render_into_pixmap(
2678 				td, td->cd, pm, acs, pixels, solid_flags,
2679 				stretch_flags, TBMP_LEFT_OF_TEXT, dest_pix, w,
2680 				NULL, &td->layout.title_g, bs, &left_of_text_g);
2681 		}
2682 		if (right_of_text_g.width > 0 && right_of_text_g.height > 0)
2683 		{
2684 			border_mp_render_into_pixmap(
2685 				td, td->cd, pm, acs, pixels, solid_flags,
2686 				stretch_flags, TBMP_RIGHT_OF_TEXT, dest_pix, w,
2687 				NULL, &td->layout.title_g, bs, &right_of_text_g);
2688 		}
2689 	}
2690 	if (left_end_g.width > 0 && left_end_g.height > 0)
2691 	{
2692 		border_mp_render_into_pixmap(
2693 			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2694 			TBMP_LEFT_END, dest_pix, w, NULL, &td->layout.title_g,
2695 			bs, &left_end_g);
2696 	}
2697 	if (right_end_g.width > 0 && right_end_g.height > 0)
2698 	{
2699 		border_mp_render_into_pixmap(
2700 			td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2701 			TBMP_RIGHT_END, dest_pix, w, NULL, &td->layout.title_g,
2702 			bs, &right_end_g);
2703 	}
2704 
2705 	return;
2706 }
2707 
2708 /*
2709  *
2710  *  draw title bar and buttons
2711  *
2712  */
border_draw_decor_to_pixmap(FvwmWindow * fw,Pixmap dest_pix,Window w,pixmap_background_type * solid_bg,rectangle * w_g,DecorFace * df,titlebar_descr * td,ButtonState bs,int use_title_style,int is_toggled,int left1right0)2713 static void border_draw_decor_to_pixmap(
2714 	FvwmWindow *fw, Pixmap dest_pix, Window w,
2715 	pixmap_background_type *solid_bg, rectangle *w_g,
2716 	DecorFace *df, titlebar_descr *td, ButtonState bs,
2717 	int use_title_style, int is_toggled, int left1right0)
2718 {
2719 	register DecorFaceType type = DFS_FACE_TYPE(df->style);
2720 	pixmap_background_type bg;
2721 	rectangle dest_g;
2722 	FvwmPicture *p;
2723 	int width,height;
2724 	int border;
2725 	int lr_just, tb_just;
2726 	common_decorations_type *cd;
2727 
2728 	cd = td->cd;
2729 	/* setup some default */
2730 	bg.pixmap.fra.mask = 0;
2731 	bg.pixmap.flags.is_stretched = 0;
2732 	bg.pixmap.flags.is_tiled = 0;
2733 	bg.flags.use_pixmap = 0;
2734 	bg.pixmap.g.x = 0;
2735 	bg.pixmap.g.y = 0;
2736 
2737 	if (DFS_BUTTON_RELIEF(df->style) == DFS_BUTTON_IS_FLAT)
2738 	{
2739 		border = 0;
2740 	}
2741 	else
2742 	{
2743 		border = HAS_MWM_BORDER(fw) ? 1 : 2;
2744 	}
2745 	dest_g.width = w_g->width;
2746 	dest_g.height = w_g->height;
2747 	dest_g.x = border;
2748 	dest_g.y = border;
2749 
2750 	switch (type)
2751 	{
2752 	case SimpleButton:
2753 		/* do nothing */
2754 		break;
2755 	case SolidButton:
2756 		/* overwrite with the default background */
2757 		dest_g.x = 0;
2758 		dest_g.y = 0;
2759 		border_fill_pixmap_background(dest_pix, &dest_g, solid_bg, cd);
2760 		break;
2761 	case VectorButton:
2762 	case DefaultVectorButton:
2763 		border_draw_vector_to_pixmap(
2764 			dest_pix, cd, is_toggled, &df->u.vector, w_g);
2765 		break;
2766 	case MiniIconButton:
2767 	case PixmapButton:
2768 	case ShrunkPixmapButton:
2769 	case StretchedPixmapButton:
2770 		if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
2771 		{
2772 			break;
2773 		}
2774 		if (FMiniIconsSupported && type == MiniIconButton)
2775 		{
2776 			if (!fw->mini_icon)
2777 			{
2778 				break;
2779 			}
2780 			p = fw->mini_icon;
2781 			if (cd->cs >= 0)
2782 			{
2783 				bg.pixmap.fra.mask |= FRAM_HAVE_ICON_CSET;
2784 				bg.pixmap.fra.colorset = &Colorset[cd->cs];
2785 			}
2786 		}
2787 		else
2788 		{
2789 			p = df->u.p;
2790 		}
2791 		width = p->width;
2792 		height = p->height;
2793 		if ((type == ShrunkPixmapButton || type == MiniIconButton) &&
2794 		    (p->width > w_g->width - 2*border ||
2795 		     p->height > w_g->height - 2*border))
2796 		{
2797 			/* do so that the picture fit into the destination */
2798 			bg.pixmap.stretch_w = width =
2799 				min(w_g->width - 2*border, p->width);
2800 			bg.pixmap.stretch_h = height =
2801 				min(w_g->height - 2*border, p->height);
2802 			bg.pixmap.flags.is_stretched = 1;
2803 		}
2804 		else if (type == StretchedPixmapButton &&
2805 			 (p->width < w_g->width - 2*border ||
2806 			  p->height < w_g->height - 2*border))
2807 		{
2808 			/* do so that the picture fit into the destination */
2809 			bg.pixmap.stretch_w = width =
2810 				max(w_g->width - 2*border, p->width);
2811 			bg.pixmap.stretch_h = height =
2812 				max(w_g->height - 2*border, p->height);
2813 			bg.pixmap.flags.is_stretched = 1;
2814 		}
2815 		lr_just = DFS_H_JUSTIFICATION(df->style);
2816 		tb_just = DFS_V_JUSTIFICATION(df->style);
2817 		if (!td->td_is_rotated && fw->title_text_rotation != ROTATION_0)
2818 		{
2819 			if (fw->title_text_rotation == ROTATION_180)
2820 			{
2821 				switch (lr_just)
2822 				{
2823 				case JUST_LEFT:
2824 					lr_just = JUST_RIGHT;
2825 					break;
2826 				case JUST_RIGHT:
2827 					lr_just = JUST_LEFT;
2828 					break;
2829 				case JUST_CENTER:
2830 				default:
2831 					break;
2832 				}
2833 				switch (tb_just)
2834 				{
2835 				case JUST_TOP:
2836 					tb_just = JUST_BOTTOM;
2837 					break;
2838 				case JUST_BOTTOM:
2839 					tb_just = JUST_TOP;
2840 					break;
2841 				case JUST_CENTER:
2842 				default:
2843 					break;
2844 				}
2845 			}
2846 			else if (fw->title_text_rotation == ROTATION_90)
2847 			{
2848 				switch (lr_just)
2849 				{
2850 				case JUST_LEFT:
2851 					tb_just = JUST_TOP;
2852 					break;
2853 				case JUST_RIGHT:
2854 					tb_just = JUST_BOTTOM;
2855 					break;
2856 				case JUST_CENTER:
2857 				default:
2858 					tb_just = JUST_CENTER;
2859 					break;
2860 				}
2861 				switch (DFS_V_JUSTIFICATION(df->style))
2862 				{
2863 				case JUST_TOP:
2864 					lr_just = JUST_RIGHT;
2865 					break;
2866 				case JUST_BOTTOM:
2867 					lr_just = JUST_LEFT;
2868 					break;
2869 				case JUST_CENTER:
2870 				default:
2871 					lr_just = JUST_CENTER;
2872 					break;
2873 				}
2874 			}
2875 			else if (fw->title_text_rotation == ROTATION_270)
2876 			{
2877 				switch (lr_just)
2878 				{
2879 				case JUST_LEFT:
2880 					tb_just = JUST_BOTTOM;
2881 					break;
2882 				case JUST_RIGHT:
2883 					tb_just = JUST_TOP;
2884 					break;
2885 				case JUST_CENTER:
2886 				default:
2887 					tb_just = JUST_CENTER;
2888 					break;
2889 				}
2890 				switch (DFS_V_JUSTIFICATION(df->style))
2891 				{
2892 				case JUST_TOP:
2893 					lr_just = JUST_LEFT;
2894 					break;
2895 				case JUST_BOTTOM:
2896 					lr_just = JUST_RIGHT;
2897 					break;
2898 				case JUST_CENTER:
2899 				default:
2900 					lr_just = JUST_CENTER;
2901 					break;
2902 				}
2903 			}
2904 		}
2905 		switch (lr_just)
2906 		{
2907 		case JUST_LEFT:
2908 			dest_g.x = border;
2909 			break;
2910 		case JUST_RIGHT:
2911 			dest_g.x = (int)(w_g->width - width - border);
2912 			break;
2913 		case JUST_CENTER:
2914 		default:
2915 			/* round down */
2916 			dest_g.x = (int)(w_g->width - width) / 2;
2917 			break;
2918 		}
2919 		switch (tb_just)
2920 		{
2921 		case JUST_TOP:
2922 			dest_g.y = border;
2923 			break;
2924 		case JUST_BOTTOM:
2925 			dest_g.y = (int)(w_g->height - height - border);
2926 			break;
2927 		case JUST_CENTER:
2928 		default:
2929 			/* round down */
2930 			dest_g.y = (int)(w_g->height - height) / 2;
2931 			break;
2932 		}
2933 		if (dest_g.x < border)
2934 		{
2935 			dest_g.x = border;
2936 		}
2937 		if (dest_g.y < border)
2938 		{
2939 			dest_g.y = border;
2940 		}
2941 		bg.flags.use_pixmap = 1;
2942 		bg.pixmap.p = p->picture;
2943 		bg.pixmap.shape = p->mask;
2944 		bg.pixmap.alpha = p->alpha;
2945 		bg.pixmap.depth = p->depth;
2946 		bg.pixmap.g.width = p->width;
2947 		bg.pixmap.g.height = p->height;
2948 		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
2949 		break;
2950 	case TiledPixmapButton:
2951 	case AdjustedPixmapButton:
2952 		if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
2953 		{
2954 			break;
2955 		}
2956 		p = df->u.p;
2957 		if (type == TiledPixmapButton)
2958 		{
2959 			bg.pixmap.flags.is_tiled = 1;
2960 		}
2961 		else
2962 		{
2963 			bg.pixmap.stretch_w = width = w_g->width - 2*dest_g.x;
2964 			bg.pixmap.stretch_h = height = w_g->height - 2*dest_g.y;
2965 			bg.pixmap.flags.is_stretched = 1;
2966 		}
2967 		bg.flags.use_pixmap = 1;
2968 		bg.pixmap.p = p->picture;
2969 		bg.pixmap.shape = p->mask;
2970 		bg.pixmap.alpha = p->alpha;
2971 		bg.pixmap.depth = p->depth;
2972 		bg.pixmap.g.width = p->width;
2973 		bg.pixmap.g.height = p->height;
2974 		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
2975 		break;
2976 	case MultiPixmap: /* for UseTitleStyle only */
2977 	{
2978 		int is_left = left1right0;
2979 		int part = TBMP_NONE;
2980 		int ap, cs;
2981 		unsigned int stretch;
2982 		Pixmap tmp = None;
2983 		FvwmPicture *full_pic = NULL;
2984 		rectangle g;
2985 		dynamic_common_decorations *dcd = &(cd->dynamic_cd);
2986 		FvwmPicture **pm;
2987 		FvwmAcs *acs;
2988 		Pixel *pixels;
2989 		unsigned short sf;
2990 
2991 		pm = df->u.mp.pixmaps;
2992 		acs = df->u.mp.acs;
2993 		pixels = df->u.mp.pixels;
2994 		sf = df->u.mp.solid_flags;
2995 		if (!border_mp_get_use_title_style_parts_and_geometry(
2996 			td, pm, acs, sf, is_left, &g, &part))
2997 		{
2998 			g.width = 0;
2999 			g.height = 0;
3000 			g.x = 0;
3001 			g.y = 0;
3002 		}
3003 
3004 		if (part == TBMP_NONE)
3005 		{
3006 			break;
3007 		}
3008 
3009 		if (sf & (1 << part))
3010 		{
3011 			bg.flags.use_pixmap = 0;
3012 			bg.pixel = pixels[part];
3013 			border_fill_pixmap_background(
3014 				dest_pix, &dest_g, &bg, cd);
3015 			break;
3016 		}
3017 		cs = acs[part].cs;
3018 		ap =  acs[part].alpha_percent;
3019 		if (CSET_IS_TRANSPARENT_PR(cs))
3020 		{
3021 			break;
3022 		}
3023 		if (cs >= 0)
3024 		{
3025 			bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
3026 			bg.pixmap.fra.added_alpha_percent = ap;
3027 		}
3028 		stretch = !!(df->u.mp.stretch_flags & (1 << part));
3029 		bg.flags.use_pixmap = 1;
3030 		dest_g.x = 0;
3031 		dest_g.y = 0;
3032 
3033 		if (cs >= 0 && use_title_style && g.width > 0 && g.height > 0 &&
3034 		    !CSET_IS_TRANSPARENT_ROOT(cs) &&
3035 		    (bg.pixmap.p = border_get_bar_pixmaps(
3036 			    dcd, &g, bs, cs, NULL, part, stretch, NULL)) != None)
3037 		{
3038 			bg.pixmap.g.width = g.width;
3039 			bg.pixmap.g.height = g.height;
3040 			bg.pixmap.flags.is_tiled = 1;
3041 			bg.pixmap.g.x = w_g->x - g.x;
3042 			bg.pixmap.g.y = w_g->y - g.y;
3043 			bg.pixmap.shape = None;
3044 			bg.pixmap.alpha = None;
3045 			bg.pixmap.depth = Pdepth;
3046 		}
3047 		else if (CSET_IS_TRANSPARENT_ROOT(cs))
3048 		{
3049 			tmp = border_create_root_transparent_pixmap(
3050 				td, w, w_g->width, w_g->height, cs);
3051 			bg.pixmap.p = tmp;
3052 			bg.pixmap.g.width = w_g->width;
3053 			bg.pixmap.g.height = w_g->height;
3054 			bg.pixmap.shape = None;
3055 			bg.pixmap.alpha = None;
3056 			bg.pixmap.depth = Pdepth;
3057 		}
3058 		else if (cs >= 0)
3059 		{
3060 			int bg_w, bg_h;
3061 
3062 			tmp = CreateBackgroundPixmap(
3063 				dpy, w, w_g->width,
3064 				w_g->height, &Colorset[cs],
3065 				Pdepth, Scr.BordersGC, False);
3066 			bg.pixmap.p = tmp;
3067 			GetWindowBackgroundPixmapSize(
3068 				&Colorset[cs], w_g->width,
3069 				w_g->height, &bg_w, &bg_h);
3070 			bg.pixmap.g.width = bg_w;
3071 			bg.pixmap.g.height = bg_h;
3072 			bg.pixmap.shape = None;
3073 			bg.pixmap.alpha = None;
3074 			bg.pixmap.depth = Pdepth;
3075 			bg.pixmap.flags.is_tiled = 1;
3076 		}
3077 		else if (pm[part] && g.width > 0 && g.height > 0 &&
3078 			 border_get_bar_pixmaps(
3079 				 dcd, &g, bs, -1, pm[part], part, stretch,
3080 				 &full_pic) != None && full_pic)
3081 		{
3082 			bg.pixmap.p = full_pic->picture;
3083 			bg.pixmap.shape = full_pic->mask;
3084 			bg.pixmap.alpha = full_pic->alpha;
3085 			bg.pixmap.depth = full_pic->depth;
3086 			bg.pixmap.g.width = full_pic->width;
3087 			bg.pixmap.g.height = full_pic->height;
3088 			bg.pixmap.g.x = w_g->x - g.x;
3089 			bg.pixmap.g.y = w_g->y - g.y;
3090 		}
3091 		else if (pm[part])
3092 		{
3093 			p = pm[part];
3094 			if (df->u.mp.stretch_flags & (1 << part))
3095 			{
3096 				bg.pixmap.flags.is_stretched = 1;
3097 			}
3098 			else
3099 			{
3100 				bg.pixmap.flags.is_tiled = 1;
3101 			}
3102 			bg.pixmap.p = p->picture;
3103 			bg.pixmap.shape = p->mask;
3104 			bg.pixmap.alpha = p->alpha;
3105 			bg.pixmap.depth = p->depth;
3106 			bg.pixmap.g.width = p->width;
3107 			bg.pixmap.g.height = p->height;
3108 			bg.pixmap.stretch_w = dest_g.width - dest_g.x;
3109 			bg.pixmap.stretch_h = dest_g.height - dest_g.y;
3110 		}
3111 		else
3112 		{
3113 			/* should not happen */
3114 			return;
3115 		}
3116 		if (bg.pixmap.p != None)
3117 		{
3118 			border_fill_pixmap_background(
3119 				dest_pix, &dest_g, &bg, cd);
3120 		}
3121 		if (tmp != None)
3122 		{
3123 			XFreePixmap(dpy, tmp);
3124 		}
3125 		break;
3126 	}
3127 	case ColorsetButton:
3128 	{
3129 		colorset_t *cs_t = &Colorset[df->u.acs.cs];
3130 		int cs = df->u.acs.cs;
3131 		Pixmap tmp = None;
3132 		int bg_w, bg_h;
3133 
3134 		if (CSET_IS_TRANSPARENT_PR(cs))
3135 		{
3136 			break;
3137 		}
3138 		dest_g.x = 0;
3139 		dest_g.y = 0;
3140 		if (use_title_style &&
3141 		    !CSET_IS_TRANSPARENT_ROOT(cs) &&
3142 		    (bg.pixmap.p = border_get_bar_pixmaps(
3143 			    &(cd->dynamic_cd), &(td->bar_g), bs, cs, NULL,
3144 			    TBMP_NONE, 0, NULL))
3145 		    != None)
3146 		{
3147 			bg.pixmap.g.width = td->bar_g.width;
3148 			bg.pixmap.g.height = td->bar_g.height;
3149 			bg.pixmap.g.x = w_g->x - td->bar_g.x;
3150 			bg.pixmap.g.y = w_g->y - td->bar_g.y;
3151 		}
3152 		else if (CSET_IS_TRANSPARENT_ROOT(cs))
3153 		{
3154 			tmp = border_create_root_transparent_pixmap(
3155 				td, w, w_g->width, w_g->height, cs);
3156 			if (tmp == None)
3157 			{
3158 				break;
3159 			}
3160 			bg.pixmap.p = tmp;
3161 			bg.pixmap.g.width = w_g->width;
3162 			bg.pixmap.g.height = w_g->height;
3163 			bg.pixmap.shape = None;
3164 			bg.pixmap.alpha = None;
3165 			bg.pixmap.depth = Pdepth;
3166 		}
3167 		else
3168 		{
3169 			tmp = CreateBackgroundPixmap(
3170 				dpy, w, w_g->width, w_g->height,
3171 				cs_t, Pdepth, Scr.BordersGC, False);
3172 			if (tmp == None)
3173 			{
3174 				break;
3175 			}
3176 			bg.pixmap.p = tmp;
3177 			GetWindowBackgroundPixmapSize(
3178 				cs_t, w_g->width, w_g->height,
3179 				&bg_w, &bg_h);
3180 			bg.pixmap.g.width = bg_w;
3181 			bg.pixmap.g.height = bg_h;
3182 			bg.pixmap.g.x = 0;
3183 			bg.pixmap.g.y = 0;
3184 		}
3185 		bg.flags.use_pixmap = 1;
3186 		bg.pixmap.shape = None;
3187 		bg.pixmap.alpha = None;
3188 		bg.pixmap.depth = Pdepth;
3189 		bg.pixmap.flags.is_tiled = 1;
3190 		bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
3191 		bg.pixmap.fra.added_alpha_percent = df->u.acs.alpha_percent;
3192 		border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
3193 		if (tmp)
3194 		{
3195 			XFreePixmap(dpy, tmp);
3196 		}
3197 		break;
3198 	}
3199 	case GradientButton:
3200 		/* draw the gradient into the pixmap */
3201 		CreateGradientPixmap(
3202 			dpy, dest_pix, Scr.TransMaskGC,
3203 			df->u.grad.gradient_type, 0, 0, df->u.grad.npixels,
3204 			df->u.grad.xcs, df->u.grad.do_dither,
3205 			&df->u.grad.d_pixels, &df->u.grad.d_npixels,
3206 			dest_pix, 0, 0, w_g->width, w_g->height, NULL);
3207 
3208 		break;
3209 
3210 	default:
3211 		fvwm_debug(__func__, "unknown button type: %i", type);
3212 		break;
3213 	}
3214 
3215 	return;
3216 }
3217 
border_set_button_pixmap(FvwmWindow * fw,titlebar_descr * td,int button,Pixmap * dest_pix,Window w)3218 static void border_set_button_pixmap(
3219 	FvwmWindow *fw, titlebar_descr *td, int button, Pixmap *dest_pix,
3220 	Window w)
3221 {
3222 	pixmap_background_type bg;
3223 	unsigned int mask;
3224 	int is_left_button;
3225 	int do_reverse_relief;
3226 	ButtonState bs;
3227 	DecorFace *df;
3228 	rectangle *button_g;
3229 	GC rgc;
3230 	GC sgc;
3231 	Bool free_bg_pixmap = False;
3232 	rectangle pix_g;
3233 
3234 	/* prepare variables */
3235 	mask = (1 << button);
3236 	if (td->has_an_upsidedown_rotation)
3237 	{
3238 		is_left_button = (button & 1);
3239 	}
3240 	else
3241 	{
3242 		is_left_button = !(button & 1);
3243 	}
3244 	button_g = &td->layout.button_g[button];
3245 	bs = td->tbstate.bstate[button];
3246 	df = &TB_STATE(GetDecor(fw, buttons[button]))[bs];
3247 	rgc = td->cd->relief_gc;
3248 	sgc = td->cd->shadow_gc;
3249 	/* prepare background, either from the window colour or from the
3250 	 * border style */
3251 	if (!DFS_USE_BORDER_STYLE(df->style))
3252 	{
3253 		/* fill with the button background colour */
3254 		bg.flags.use_pixmap = 0;
3255 		bg.pixel = td->cd->back_color;
3256 		pix_g.x = 0;
3257 		pix_g.y = 0;
3258 		pix_g.width = button_g->width;
3259 		pix_g.height = button_g->height;
3260 		border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
3261 	}
3262 	else
3263 	{
3264 		/* draw pixmap background inherited from border style */
3265 		rectangle relative_g;
3266 
3267 		relative_g.width = td->frame_g.width;
3268 		relative_g.height = td->frame_g.height;
3269 		relative_g.x = button_g->x;
3270 		relative_g.y = button_g->y;
3271 		border_get_border_background(
3272 			&bg, td->cd, button_g, &relative_g, &free_bg_pixmap, w);
3273 		bg.pixmap.g.x = 0;
3274 		bg.pixmap.g.y = 0;
3275 		/* set the geometry for drawing the Tiled pixmap;
3276 		 * FIXME: maybe add the relief as offset? */
3277 		pix_g.x = 0;
3278 		pix_g.y = 0;
3279 		pix_g.width = button_g->width;
3280 		pix_g.height = button_g->height;
3281 		border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
3282 		if (free_bg_pixmap && bg.pixmap.p)
3283 		{
3284 			XFreePixmap(dpy, bg.pixmap.p);
3285 		}
3286 	}
3287 
3288 	/* handle title style */
3289 	if (DFS_USE_TITLE_STYLE(df->style))
3290 	{
3291 		/* draw background inherited from title style */
3292 		DecorFace *tsdf;
3293 		Pixmap tmp;
3294 
3295 		if (td->draw_rotation != ROTATION_0)
3296 		{
3297 			tmp = CreateRotatedPixmap(
3298 				dpy, *dest_pix,
3299 				td->layout.button_g[button].width,
3300 				td->layout.button_g[button].height,
3301 				Pdepth, Scr.BordersGC, td->restore_rotation);
3302 			XFreePixmap(dpy, *dest_pix);
3303 			*dest_pix = tmp;
3304 			border_rotate_titlebar_descr(fw, td);
3305 			button_g = &td->layout.button_g[button];
3306 			is_left_button = !(button & 1);
3307 		}
3308 		for (tsdf = &TB_STATE(GetDecor(fw, titlebar))[bs]; tsdf != NULL;
3309 		     tsdf = tsdf->next)
3310 		{
3311 			bg.pixel = tsdf->u.back;
3312 			border_draw_decor_to_pixmap(
3313 				fw, *dest_pix, w, &bg, button_g, tsdf, td,
3314 				bs, True, (td->tbstate.toggled_bmask & mask),
3315 				is_left_button);
3316 		}
3317 		if (td->draw_rotation != ROTATION_0)
3318 		{
3319 			tmp = CreateRotatedPixmap(
3320 				dpy, *dest_pix,
3321 				td->layout.button_g[button].width,
3322 				td->layout.button_g[button].height,
3323 				Pdepth, Scr.BordersGC, td->draw_rotation);
3324 			XFreePixmap(dpy, *dest_pix);
3325 			*dest_pix = tmp;
3326 			border_rotate_titlebar_descr(fw, td);
3327 			button_g = &td->layout.button_g[button];
3328 			if (td->has_an_upsidedown_rotation)
3329 			{
3330 				is_left_button = (button & 1);
3331 			}
3332 			else
3333 			{
3334 				is_left_button = !(button & 1);
3335 			}
3336 		}
3337 	}
3338 	/* handle button style */
3339 	for ( ; df; df = df->next)
3340 	{
3341 		/* draw background from button style */
3342 		bg.pixel = df->u.back;
3343 		border_draw_decor_to_pixmap(
3344 			fw, *dest_pix, w, &bg, button_g, df, td, bs, False,
3345 			(td->tbstate.toggled_bmask & mask), is_left_button);
3346 	}
3347 	/* draw the button relief */
3348 	do_reverse_relief = !!(td->tbstate.pressed_bmask & mask);
3349 	switch (DFS_BUTTON_RELIEF(
3350 			TB_STATE(GetDecor(fw, buttons[button]))[bs].style))
3351 	{
3352 	case DFS_BUTTON_IS_SUNK:
3353 		do_reverse_relief ^= 1;
3354 		/* fall through*/
3355 	case DFS_BUTTON_IS_UP:
3356 		do_relieve_rectangle(
3357 			dpy, *dest_pix, 0, 0, button_g->width - 1,
3358 			button_g->height - 1,
3359 			(do_reverse_relief) ? sgc : rgc,
3360 			(do_reverse_relief) ? rgc : sgc,
3361 			td->cd->relief_width, True);
3362 		break;
3363 	default:
3364 		/* flat */
3365 		break;
3366 	}
3367 
3368 	return;
3369 }
3370 
border_draw_one_button(FvwmWindow * fw,titlebar_descr * td,int button)3371 static void border_draw_one_button(
3372 	FvwmWindow *fw, titlebar_descr *td, int button)
3373 {
3374 	Pixmap p;
3375 
3376 	/* make a pixmap */
3377 	if (td->layout.button_g[button].x < 0 ||
3378 	    td->layout.button_g[button].y < 0)
3379 	{
3380 		return;
3381 	}
3382 
3383 	p = border_create_decor_pixmap(td->cd, &(td->layout.button_g[button]));
3384 	/* set the background tile */
3385 	border_set_button_pixmap(fw, td, button, &p, FW_W_BUTTON(fw, button));
3386 	/* apply the pixmap and destroy it */
3387 	border_set_part_background(FW_W_BUTTON(fw, button), p);
3388 	XFreePixmap(dpy, p);
3389 	if ((td->tbstate.clear_bmask & (1 << button)) != 0)
3390 	{
3391 		XClearWindow(dpy, FW_W_BUTTON(fw, button));
3392 	}
3393 
3394 	return;
3395 }
3396 
border_draw_title_stick_lines(FvwmWindow * fw,titlebar_descr * td,title_draw_descr * tdd,Pixmap dest_pix)3397 static void border_draw_title_stick_lines(
3398 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3399 	Pixmap dest_pix)
3400 {
3401 	int i;
3402 	int num;
3403 	int min;
3404 	int max;
3405 	int left_x;
3406 	int left_w;
3407 	int right_x;
3408 	int right_w;
3409 	int under_text_length = 0;
3410 	int under_text_offset = 0;
3411 	int right_length = 0;
3412 	int left_length = 0;
3413 	rotation_t rotation;
3414 
3415 	if (!( (HAS_STICKY_STIPPLED_TITLE(fw) &&
3416 		(IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
3417 	       || HAS_STIPPLED_TITLE(fw)))
3418 	{
3419 		return;
3420 	}
3421 	if (td->td_is_rotated)
3422 	{
3423 		rotation = td->restore_rotation;
3424 	}
3425 	else
3426 	{
3427 		rotation = ROTATION_0;
3428 	}
3429 	if (td->has_vt && td->under_text_g.height > 0)
3430 	{
3431 		under_text_length = td->under_text_g.height;
3432 		under_text_offset = td->under_text_g.y;
3433 		left_length = td->left_main_g.height - td->left_of_text_length
3434 			- td->left_end_length;
3435 		right_length = td->right_main_g.height -
3436 			td->right_of_text_length - td->right_end_length;
3437 
3438 	}
3439 	else if (!td->has_vt && td->under_text_g.width > 0)
3440 	{
3441 		under_text_length = td->under_text_g.width;
3442 		under_text_offset = td->under_text_g.x;
3443 		left_length = td->left_main_g.width - td->left_of_text_length
3444 			- td->left_end_length;
3445 		right_length = td->right_main_g.width -
3446 			td->right_of_text_length - td->right_end_length;
3447 	}
3448 
3449 	/* If the window is sticky either across pages or
3450 	 * desks and it has a stippled title, but nothing for
3451 	 * sticky_stippled_title, then don't bother drawing them, just
3452 	 * return immediately. -- Thomas Adam
3453 	 */
3454 	if ( (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)) &&
3455 	    (!HAS_STICKY_STIPPLED_TITLE(fw) && HAS_STIPPLED_TITLE(fw)) )
3456 	{
3457 		return;
3458 	}
3459 
3460 	num = (int)(fw->title_thickness / WINDOW_TITLE_STICK_VERT_DIST / 2) *
3461 		2 - 1;
3462 	min = fw->title_thickness / 2 - num * 2 + 1;
3463 	max = fw->title_thickness / 2 + num * 2 -
3464 		WINDOW_TITLE_STICK_VERT_DIST + 1;
3465 	left_x = WINDOW_TITLE_STICK_OFFSET + td->left_end_length;
3466 	left_w = ((under_text_length == 0)? td->offset:under_text_offset)
3467 		- left_x - WINDOW_TITLE_TO_STICK_GAP - td->left_of_text_length;
3468 	right_x = ((under_text_length == 0)?
3469 		   td->offset + td->length :
3470 		   under_text_offset + under_text_length)
3471 		+ td->right_of_text_length + WINDOW_TITLE_TO_STICK_GAP - 1;
3472 	right_w = fw->title_length - right_x - WINDOW_TITLE_STICK_OFFSET
3473 		- td->right_end_length;
3474 	/* an odd number of lines every WINDOW_TITLE_STICK_VERT_DIST pixels */
3475 	if (left_w < WINDOW_TITLE_STICK_MIN_WIDTH)
3476 	{
3477 		left_x = td->left_end_length +
3478 			((left_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
3479 			 (left_length - WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
3480 		left_w = WINDOW_TITLE_STICK_MIN_WIDTH;
3481 	}
3482 	if (right_w < WINDOW_TITLE_STICK_MIN_WIDTH)
3483 	{
3484 		right_w = WINDOW_TITLE_STICK_MIN_WIDTH;
3485 		right_x = fw->title_length - WINDOW_TITLE_STICK_MIN_WIDTH - 1
3486 			- td->right_end_length -
3487 			((right_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
3488 			 (right_length -
3489 			  WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
3490 	}
3491 	for (i = min; i <= max; i += WINDOW_TITLE_STICK_VERT_DIST)
3492 	{
3493 		if (left_w > 0)
3494 		{
3495 			do_relieve_rectangle_with_rotation(
3496 				dpy, dest_pix,
3497 				SWAP_ARGS(td->has_vt, left_x, i),
3498 				SWAP_ARGS(td->has_vt, left_w, 1),
3499 				tdd->sgc, tdd->rgc, 1, False, rotation);
3500 		}
3501 		if (right_w > 0)
3502 		{
3503 			do_relieve_rectangle_with_rotation(
3504 				dpy, dest_pix,
3505 				SWAP_ARGS(td->has_vt, right_x, i),
3506 				SWAP_ARGS(td->has_vt, right_w, 1),
3507 				tdd->sgc, tdd->rgc, 1, False, rotation);
3508 		}
3509 	}
3510 
3511 	return;
3512 }
3513 
border_draw_title_mono(FvwmWindow * fw,titlebar_descr * td,title_draw_descr * tdd,FlocaleWinString * fstr,Pixmap dest_pix)3514 static void border_draw_title_mono(
3515 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3516 	FlocaleWinString *fstr, Pixmap dest_pix)
3517 {
3518 	int has_vt;
3519 
3520 	has_vt = HAS_VERTICAL_TITLE(fw);
3521 	XFillRectangle(
3522 		dpy, dest_pix, td->cd->relief_gc,
3523 		td->offset - 2, 0, td->length+4, fw->title_thickness);
3524 	if (fw->visible_name != (char *)NULL)
3525 	{
3526 		FlocaleDrawString(dpy, fw->title_font, fstr, 0);
3527 	}
3528 	/* for mono, we clear an area in the title bar where the window
3529 	 * title goes, so that its more legible. For color, no need */
3530 	do_relieve_rectangle(
3531 		dpy, dest_pix, 0, 0,
3532 		SWAP_ARGS(has_vt, td->offset - 3,
3533 			  fw->title_thickness - 1),
3534 		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
3535 	do_relieve_rectangle(
3536 		dpy, dest_pix,
3537 		SWAP_ARGS(has_vt, td->offset + td->length + 2, 0),
3538 		SWAP_ARGS(has_vt, fw->title_length - td->length -
3539 			  td->offset - 3, fw->title_thickness - 1),
3540 		tdd->rgc, tdd->sgc, td->cd->relief_width, False);
3541 	XDrawLine(
3542 		dpy, dest_pix, tdd->sgc,
3543 		SWAP_ARGS(has_vt, 0, td->offset + td->length + 1),
3544 		SWAP_ARGS(has_vt, td->offset + td->length + 1,
3545 			  fw->title_thickness));
3546 
3547 	return;
3548 }
3549 
border_draw_title_relief(FvwmWindow * fw,titlebar_descr * td,title_draw_descr * tdd,Pixmap dest_pix)3550 static void border_draw_title_relief(
3551 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3552 	Pixmap dest_pix)
3553 {
3554 	int reverse = 0;
3555 	rotation_t rotation;
3556 
3557 	if (td->td_is_rotated)
3558 	{
3559 		rotation = td->restore_rotation;
3560 	}
3561 	else
3562 	{
3563 		rotation = ROTATION_0;
3564 	}
3565 	/* draw title relief */
3566 	switch (DFS_BUTTON_RELIEF(*tdd->tstyle))
3567 	{
3568 	case DFS_BUTTON_IS_SUNK:
3569 		reverse = 1;
3570 	case DFS_BUTTON_IS_UP:
3571 		do_relieve_rectangle_with_rotation(
3572 			dpy, dest_pix, 0, 0,
3573 			SWAP_ARGS(
3574 				td->has_vt, fw->title_length - 1,
3575 				fw->title_thickness - 1),
3576 			(reverse) ? tdd->sgc : tdd->rgc,
3577 			(reverse) ? tdd->rgc : tdd->sgc, td->cd->relief_width,
3578 			True, rotation);
3579 		break;
3580 	default:
3581 		/* flat */
3582 		break;
3583 	}
3584 
3585 	return;
3586 }
3587 
border_draw_title_deep(FvwmWindow * fw,titlebar_descr * td,title_draw_descr * tdd,FlocaleWinString * fstr,Pixmap dest_pix,Window w)3588 static void border_draw_title_deep(
3589 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3590 	FlocaleWinString *fstr, Pixmap dest_pix, Window w)
3591 {
3592 	DecorFace *df;
3593 	pixmap_background_type bg;
3594 
3595 	bg.flags.use_pixmap = 0;
3596 	for (df = tdd->df; df != NULL; df = df->next)
3597 	{
3598 		if (df->style.face_type == MultiPixmap)
3599 		{
3600 			border_mp_draw_mp_titlebar(
3601 				fw, td, df, dest_pix, w);
3602 		}
3603 		else
3604 		{
3605 			bg.pixel = df->u.back;
3606 			border_draw_decor_to_pixmap(
3607 				fw, dest_pix, w, &bg, &td->layout.title_g, df,
3608 				td, td->tbstate.tstate, True, tdd->is_toggled,
3609 				1);
3610 		}
3611 	}
3612 	FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0);
3613 
3614 	return;
3615 }
3616 
border_get_titlebar_draw_descr(FvwmWindow * fw,titlebar_descr * td,title_draw_descr * tdd,Pixmap dest_pix)3617 static void border_get_titlebar_draw_descr(
3618 	FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3619 	Pixmap dest_pix)
3620 {
3621 	memset(tdd, 0, sizeof(*tdd));
3622 	/* prepare the gcs and variables */
3623 	if (td->tbstate.is_title_pressed)
3624 	{
3625 		tdd->rgc = td->cd->shadow_gc;
3626 		tdd->sgc = td->cd->relief_gc;
3627 	}
3628 	else
3629 	{
3630 		tdd->rgc = td->cd->relief_gc;
3631 		tdd->sgc = td->cd->shadow_gc;
3632 	}
3633 	NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color);
3634 	tdd->tstyle = &TB_STATE(
3635 		GetDecor(fw, titlebar))[td->tbstate.tstate].style;
3636 	tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
3637 
3638 	/* fetch the title string */
3639 	tdd->fstr.str = fw->visible_name;
3640 	tdd->fstr.win = dest_pix;
3641 	if (td->td_is_rotated)
3642 	{
3643 		tdd->fstr.flags.text_rotation = ROTATION_0;
3644 	}
3645 	else
3646 	{
3647 		tdd->fstr.flags.text_rotation = fw->title_text_rotation;
3648 	}
3649 	if (td->has_vt)
3650 	{
3651 		tdd->fstr.y = td->offset;
3652 		tdd->fstr.x = fw->title_text_offset + 1;
3653 	}
3654 	else
3655 	{
3656 		tdd->fstr.x = td->offset;
3657 		tdd->fstr.y = fw->title_text_offset + 1;
3658 	}
3659 	if (td->cd->cs >= 0)
3660 	{
3661 		tdd->fstr.colorset = &Colorset[td->cd->cs];
3662 		tdd->fstr.flags.has_colorset = 1;
3663 	}
3664 	tdd->fstr.gc = Scr.TitleGC;
3665 
3666 	return;
3667 }
3668 
border_set_title_pixmap(FvwmWindow * fw,titlebar_descr * td,Pixmap * dest_pix,Window w)3669 static void border_set_title_pixmap(
3670 	FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w)
3671 {
3672 	pixmap_background_type bg;
3673 	title_draw_descr tdd;
3674 	FlocaleWinString fstr;
3675 	Bool free_bg_pixmap = False;
3676 	rectangle pix_g;
3677 
3678 	border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix);
3679 	/* prepare background, either from the window colour or from the
3680 	 * border style */
3681 	if (!DFS_USE_BORDER_STYLE(*tdd.tstyle))
3682 	{
3683 		/* fill with the button background colour */
3684 		bg.flags.use_pixmap = 0;
3685 		bg.pixel = td->cd->back_color;
3686 		pix_g.x = 0;
3687 		pix_g.y = 0;
3688 		pix_g.width = td->layout.title_g.width;
3689 		pix_g.height = td->layout.title_g.height;
3690 		border_fill_pixmap_background(
3691 			*dest_pix, &pix_g, &bg, td->cd);
3692 	}
3693 	else
3694 	{
3695 		/* draw pixmap background inherited from border style */
3696 		rectangle relative_g;
3697 		Pixmap tmp;
3698 
3699 		if (td->draw_rotation != ROTATION_0)
3700 		{
3701 			tmp = CreateRotatedPixmap(
3702 				dpy, *dest_pix,
3703 				td->layout.title_g.width,
3704 				td->layout.title_g.height,
3705 				Pdepth, Scr.BordersGC, td->restore_rotation);
3706 			XFreePixmap(dpy, *dest_pix);
3707 			*dest_pix = tmp;
3708 			border_rotate_titlebar_descr(fw, td);
3709 		}
3710 		relative_g.width = td->frame_g.width;
3711 		relative_g.height = td->frame_g.height;
3712 		relative_g.x = td->layout.title_g.x;
3713 		relative_g.y = td->layout.title_g.y;
3714 		border_get_border_background(
3715 			&bg, td->cd, &td->layout.title_g, &relative_g,
3716 			&free_bg_pixmap, w);
3717 		bg.pixmap.g.x = 0;
3718 		bg.pixmap.g.y = 0;
3719 		/* set the geometry for drawing the Tiled pixmap;
3720 		 * FIXME: maybe add the relief as offset? */
3721 		pix_g.x = 0;
3722 		pix_g.y = 0;
3723 		pix_g.width = td->layout.title_g.width;
3724 		pix_g.height = td->layout.title_g.height;
3725 		border_fill_pixmap_background(
3726 			*dest_pix, &pix_g, &bg, td->cd);
3727 		if (free_bg_pixmap && bg.pixmap.p)
3728 		{
3729 			XFreePixmap(dpy, bg.pixmap.p);
3730 		}
3731 		if (td->draw_rotation != ROTATION_0)
3732 		{
3733 			tmp = CreateRotatedPixmap(
3734 				dpy, *dest_pix,
3735 				td->layout.title_g.width,
3736 				td->layout.title_g.height,
3737 				Pdepth, Scr.BordersGC, td->draw_rotation);
3738 			XFreePixmap(dpy, *dest_pix);
3739 			*dest_pix = tmp;
3740 			border_rotate_titlebar_descr(fw, td);
3741 		}
3742 	}
3743 
3744 	if (Pdepth < 2)
3745 	{
3746 		border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix);
3747 	}
3748 	else
3749 	{
3750 		border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w);
3751 	}
3752 	border_draw_title_relief(fw, td, &tdd, *dest_pix);
3753 	border_draw_title_stick_lines(fw, td, &tdd, *dest_pix);
3754 
3755 	return;
3756 }
3757 
border_draw_title(FvwmWindow * fw,titlebar_descr * td)3758 static void border_draw_title(
3759 	FvwmWindow *fw, titlebar_descr *td)
3760 {
3761 	Pixmap p;
3762 
3763 	if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0)
3764 	{
3765 		return;
3766 	}
3767 	if (td->draw_rotation != ROTATION_0)
3768 	{
3769 		border_rotate_titlebar_descr(fw, td);
3770 	}
3771 	/* make a pixmap */
3772 	p = border_create_decor_pixmap(td->cd, &(td->layout.title_g));
3773 	/* set the background tile */
3774 #if 0
3775 	fprintf(stderr,"drawing title\n");
3776 #endif
3777 	border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw));
3778 	if (td->draw_rotation != ROTATION_0)
3779 	{
3780 		Pixmap tmp;
3781 
3782 		tmp = CreateRotatedPixmap(
3783 			dpy, p, td->layout.title_g.width,
3784 			td->layout.title_g.height, Pdepth, Scr.BordersGC,
3785 			td->draw_rotation);
3786 		XFreePixmap(dpy, p);
3787 		p = tmp;
3788 		border_rotate_titlebar_descr(fw, td);
3789 	}
3790 	/* apply the pixmap and destroy it */
3791 	border_set_part_background(FW_W_TITLE(fw), p);
3792 	XFreePixmap(dpy, p);
3793 	if (td->tbstate.do_clear_title)
3794 	{
3795 		XClearWindow(dpy, FW_W_TITLE(fw));
3796 	}
3797 
3798 	return;
3799 }
3800 
border_draw_buttons(FvwmWindow * fw,titlebar_descr * td)3801 static void border_draw_buttons(
3802 	FvwmWindow *fw, titlebar_descr *td)
3803 {
3804 	int i;
3805 
3806 	/* draw everything in a big loop */
3807 #if 0
3808 	fprintf(stderr, "drawing buttons 0x%04x\n", td->tbstate.draw_bmask);
3809 #endif
3810 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
3811 	{
3812 		unsigned int mask = (1 << i);
3813 
3814 		if ((td->tbstate.draw_bmask & mask) != 0)
3815 		{
3816 			border_draw_one_button(fw, td, i);
3817 		}
3818 	}
3819 	/* update the button states */
3820 	fw->decor_state.buttons_drawn |= td->tbstate.draw_bmask;
3821 	fw->decor_state.buttons_inverted = td->tbstate.pressed_bmask;
3822 	fw->decor_state.buttons_lit = td->tbstate.lit_bmask;
3823 	fw->decor_state.buttons_toggled = td->tbstate.toggled_bmask;
3824 
3825 	return;
3826 }
3827 
border_setup_use_title_style(FvwmWindow * fw,titlebar_descr * td)3828 static void border_setup_use_title_style(
3829 	FvwmWindow *fw, titlebar_descr *td)
3830 {
3831 	int i;
3832 	DecorFace *df, *tsdf;
3833 	ButtonState bs, tsbs;
3834 
3835 	/* use a full bar pixmap (for Colorset) or non window size pixmaps
3836 	 * (for MultiPixmap) under certain condition:
3837 	 * - for the buttons which use title style
3838 	 * - for title which have a button with UseTitle style
3839 	 */
3840 	tsbs = td->tbstate.tstate;
3841 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
3842 	{
3843 		bs = td->tbstate.bstate[i];
3844 		df = &TB_STATE(GetDecor(fw, buttons[i]))[bs];
3845 		tsdf = &TB_STATE(GetDecor(fw, buttons[i]))[tsbs];
3846 		if (FW_W_BUTTON(fw, i) != None)
3847 		{
3848 			if (DFS_USE_TITLE_STYLE(df->style))
3849 			{
3850 				border_setup_bar_pixmaps(
3851 					td, &(td->cd->dynamic_cd),
3852 					&TB_STATE(GetDecor(fw, titlebar))[bs],
3853 					bs);
3854 			}
3855 			if (DFS_USE_TITLE_STYLE(tsdf->style))
3856 			{
3857 				border_setup_bar_pixmaps(
3858 					td, &(td->cd->dynamic_cd),
3859 					&TB_STATE(GetDecor(fw, titlebar))[tsbs],
3860 					tsbs);
3861 			}
3862 		}
3863 	}
3864 	return;
3865 }
3866 
border_rotate_titlebar_descr(FvwmWindow * fw,titlebar_descr * td)3867 static void border_rotate_titlebar_descr(
3868 	FvwmWindow *fw, titlebar_descr *td)
3869 {
3870 	rotation_t rotation;
3871 	int i, tmpi;
3872 	static titlebar_descr saved_td;
3873 
3874 	if (td->draw_rotation == ROTATION_0)
3875 	{
3876 		return;
3877 	}
3878 	if (!td->has_been_saved)
3879 	{
3880 		td->has_been_saved = True;
3881 		memcpy(&saved_td, td, sizeof(titlebar_descr));
3882 	}
3883 	if (!td->td_is_rotated)
3884 	{
3885 		/* make the bar horizontal */
3886 		switch(td->draw_rotation)
3887 		{
3888 		case ROTATION_90: /* cw */
3889 			rotation = ROTATION_270;
3890 			break;
3891 		case ROTATION_270: /* ccw */
3892 			rotation = ROTATION_90;
3893 			break;
3894 		case ROTATION_180:
3895 			rotation = ROTATION_180;
3896 			break;
3897 		default:
3898 			return;
3899 		}
3900 		td->has_vt = 0;
3901 		td->has_an_upsidedown_rotation = 0;
3902 		td->td_is_rotated = 1;
3903 	}
3904 	else
3905 	{
3906 		/* restore */
3907 		memcpy(td, &saved_td, sizeof(titlebar_descr));
3908 		td->td_is_rotated = 0;
3909 		return;
3910 	}
3911 
3912 #define ROTATE_RECTANGLE(rot, r, vs_frame, vs_titlebar, vs_title) \
3913 	{ \
3914 		rectangle tr; \
3915 		tr.x = r->x; \
3916 		tr.y = r->y; \
3917 		tr.width = r->width; \
3918 		tr.height = r->height; \
3919 		switch(rot) \
3920 		{ \
3921 		case ROTATION_270: /* ccw */ \
3922 			tr.x = r->y; \
3923 			if (vs_frame) \
3924 			{ \
3925 				tr.y = td->frame_g.width - (r->x+r->width); \
3926 			} \
3927 			else if (vs_titlebar) \
3928 			{ \
3929 				tr.y = td->bar_g.width - \
3930 					(r->x+r->width); \
3931 			} \
3932 			else if (vs_title) \
3933 			{ \
3934 				tr.y = td->layout.title_g.width - \
3935 					(r->x+r->width); \
3936 			} \
3937 			else \
3938 			{ \
3939 				tr.y = r->x; \
3940 			} \
3941 			tr.width = r->height; \
3942 			tr.height = r->width; \
3943 			break; \
3944 		case ROTATION_90: /* cw */ \
3945 			if (vs_frame) \
3946 			{ \
3947 				tr.x = td->frame_g.height - (r->y+r->height); \
3948 			} \
3949 			else if (vs_titlebar) \
3950 			{ \
3951 				tr.x = td->bar_g.height - \
3952 					(r->y+r->height); \
3953 			} \
3954 			else if (vs_title) \
3955 			{ \
3956 				tr.x = td->layout.title_g.height - \
3957 					(r->y+r->height); \
3958 			} \
3959 			else \
3960 			{ \
3961 				tr.x = r->y; \
3962 			} \
3963 			tr.y = r->x; \
3964 			tr.width = r->height; \
3965 			tr.height = r->width; \
3966 			break; \
3967 		case ROTATION_180: \
3968 			if (vs_frame) \
3969 			{ \
3970 				tr.x = td->frame_g.width - (r->x+r->width); \
3971 			} \
3972 			else if (vs_titlebar) \
3973 			{ \
3974 				tr.x = td->bar_g.width - \
3975 					(r->x + r->width); \
3976 			} \
3977 			else if (vs_title) \
3978 			{ \
3979 				tr.x = td->layout.title_g.width - \
3980 					(r->x + r->width); \
3981 			} \
3982 			else \
3983 			{ \
3984 				tr.x = r->x; \
3985 			} \
3986 			break; \
3987 		case ROTATION_0: \
3988 			break; \
3989 		} \
3990 		r->x = tr.x; \
3991 		r->y = tr.y; \
3992 		r->width = tr.width; \
3993 		r->height = tr.height; \
3994 	}
3995 
3996 	switch(rotation)
3997 	{
3998 	case ROTATION_90:
3999 		td->offset =
4000 			td->layout.title_g.height - td->offset - td->length;
4001 		tmpi = td->left_end_length;
4002 		td->left_end_length = td->right_end_length;
4003 		td->right_end_length = tmpi;
4004 		tmpi = td->left_of_text_length;
4005 		td->left_of_text_length = td->right_of_text_length;
4006 		td->right_of_text_length = tmpi;
4007 		break;
4008 	case ROTATION_270:
4009 		break;
4010 	case ROTATION_180:
4011 		td->offset = td->layout.title_g.width - td->offset - td->length;
4012 		tmpi = td->left_end_length;
4013 		td->left_end_length = td->right_end_length;
4014 		td->right_end_length = tmpi;
4015 		tmpi = td->left_of_text_length;
4016 		td->left_of_text_length = td->right_of_text_length;
4017 		td->right_of_text_length = tmpi;
4018 		break;
4019 	case ROTATION_0:
4020 		break;
4021 	}
4022 
4023 	ROTATE_RECTANGLE(rotation, (&td->left_buttons_g), True, False, False)
4024 	ROTATE_RECTANGLE(rotation, (&td->right_buttons_g), True, False, False)
4025 	for (i=0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4026 	{
4027 		ROTATE_RECTANGLE(
4028 			rotation, (&td->layout.button_g[i]), True, False, False)
4029 	}
4030 	ROTATE_RECTANGLE(rotation, (&td->under_text_g), False, False, True)
4031 	ROTATE_RECTANGLE(rotation, (&td->left_main_g), False, False, True)
4032 	ROTATE_RECTANGLE(rotation, (&td->right_main_g), False, False, True)
4033 	ROTATE_RECTANGLE(rotation, (&td->full_left_main_g), True, False, False)
4034 	ROTATE_RECTANGLE(rotation, (&td->full_right_main_g), True, False, False)
4035 	ROTATE_RECTANGLE(rotation, (&td->layout.title_g), True, False, False)
4036 	ROTATE_RECTANGLE(rotation, (&td->bar_g), True, False, False)
4037 	ROTATE_RECTANGLE(rotation, (&td->frame_g), False, False, False);
4038 
4039 #undef ROTATE_RECTANGLE
4040 }
4041 
border_get_titlebar_descr_state(FvwmWindow * fw,window_parts pressed_parts,int pressed_button,clear_window_parts clear_parts,Bool do_hilight,border_titlebar_state * tbstate)4042 static void border_get_titlebar_descr_state(
4043 	FvwmWindow *fw, window_parts pressed_parts, int pressed_button,
4044 	clear_window_parts clear_parts, Bool do_hilight,
4045 	border_titlebar_state *tbstate)
4046 {
4047 	int i;
4048 
4049 	if ((pressed_parts & PART_BUTTONS) != PART_NONE && pressed_button >= 0)
4050 	{
4051 		tbstate->pressed_bmask = (1 << pressed_button);
4052 	}
4053 	else
4054 	{
4055 		tbstate->pressed_bmask = 0;
4056 	}
4057 	if ((clear_parts & CLEAR_BUTTONS) != CLEAR_NONE)
4058 	{
4059 		tbstate->clear_bmask = 0x3FF;
4060 	}
4061 	else
4062 	{
4063 		tbstate->clear_bmask = 0;
4064 	}
4065 	tbstate->lit_bmask = (do_hilight == True) ? ~0 : 0;
4066 	if ((pressed_parts & PART_TITLE) != PART_NONE)
4067 	{
4068 		tbstate->is_title_pressed = 1;
4069 	}
4070 	else
4071 	{
4072 		tbstate->is_title_pressed = 0;
4073 	}
4074 	if ((clear_parts & CLEAR_TITLE) != CLEAR_NONE)
4075 	{
4076 		tbstate->do_clear_title = 1;
4077 	}
4078 	else
4079 	{
4080 		tbstate->do_clear_title = 0;
4081 	}
4082 	tbstate->is_title_lit = (do_hilight == True) ? 1 : 0;
4083 	tbstate->toggled_bmask = 0;
4084 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4085 	{
4086 		unsigned int mask = (1 << i);
4087 
4088 		if (is_button_toggled(fw, i))
4089 		{
4090 			tbstate->toggled_bmask |= mask;
4091 		}
4092 		tbstate->bstate[i] = border_flags_to_button_state(
4093 			tbstate->pressed_bmask & mask,
4094 			tbstate->lit_bmask & mask,
4095 			tbstate->toggled_bmask & mask);
4096 	}
4097 	tbstate->tstate = border_flags_to_button_state(
4098 		tbstate->is_title_pressed, tbstate->is_title_lit, 0);
4099 }
4100 
border_get_titlebar_descr(common_decorations_type * cd,FvwmWindow * fw,window_parts pressed_parts,int pressed_button,window_parts force_draw_parts,clear_window_parts clear_parts,rectangle * old_g,rectangle * new_g,Bool do_hilight,titlebar_descr * ret_td)4101 static window_parts border_get_titlebar_descr(
4102 	common_decorations_type *cd, FvwmWindow *fw,
4103 	window_parts pressed_parts, int pressed_button,
4104 	window_parts force_draw_parts, clear_window_parts clear_parts,
4105 	rectangle *old_g, rectangle *new_g, Bool do_hilight,
4106 	titlebar_descr *ret_td)
4107 {
4108 	window_parts draw_parts;
4109 	int i;
4110 	DecorFace *df;
4111 	int is_start = 0;
4112 	JustificationType just;
4113 	int lbl = 0;
4114 	int rbl = 0;
4115 
4116 	ret_td->cd = cd;
4117 	ret_td->frame_g = *new_g;
4118 	if (old_g == NULL)
4119 	{
4120 		old_g = &fw->g.frame;
4121 	}
4122 	frame_get_titlebar_dimensions(fw, old_g, NULL, &ret_td->old_layout);
4123 	frame_get_titlebar_dimensions(fw, new_g, NULL, &ret_td->layout);
4124 
4125 	ret_td->has_vt = HAS_VERTICAL_TITLE(fw);
4126 	if (USE_TITLE_DECOR_ROTATION(fw))
4127 	{
4128 		ret_td->draw_rotation = fw->title_text_rotation;
4129 		switch(ret_td->draw_rotation)
4130 		{
4131 		case ROTATION_90:
4132 			ret_td->restore_rotation = ROTATION_270;
4133 			break;
4134 		case ROTATION_270: /* ccw */
4135 			ret_td->restore_rotation = ROTATION_90;
4136 			break;
4137 		case ROTATION_180:
4138 			ret_td->restore_rotation = ROTATION_180;
4139 			break;
4140 		default:
4141 			break;
4142 		}
4143 	}
4144 	if (fw->title_text_rotation == ROTATION_270 ||
4145 	    fw->title_text_rotation == ROTATION_180)
4146 	{
4147 		ret_td->has_an_upsidedown_rotation = True;
4148 	}
4149 	/* geometry of the title bar title + buttons */
4150 	if (!ret_td->has_vt)
4151 	{
4152 		ret_td->bar_g.width = new_g->width - 2 * fw->boundary_width;
4153 		ret_td->bar_g.height = ret_td->layout.title_g.height;
4154 		ret_td->bar_g.x = fw->boundary_width;
4155 		ret_td->bar_g.y = ret_td->layout.title_g.y;
4156 	}
4157 	else
4158 	{
4159 		ret_td->bar_g.width = ret_td->layout.title_g.width;
4160 		ret_td->bar_g.height = new_g->height - 2 * fw->boundary_width;
4161 		ret_td->bar_g.y = fw->boundary_width;
4162 		ret_td->bar_g.x = ret_td->layout.title_g.x;
4163 	}
4164 
4165 	/* buttons geometries */
4166 	if (ret_td->has_vt)
4167 	{
4168 		ret_td->left_buttons_g.width = ret_td->bar_g.width;
4169 		ret_td->right_buttons_g.width = ret_td->bar_g.width;
4170 	}
4171 	else
4172 	{
4173 		ret_td->left_buttons_g.height = ret_td->bar_g.height;
4174 		ret_td->right_buttons_g.height = ret_td->bar_g.width;
4175 	}
4176 
4177 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4178 	{
4179 		if (FW_W_BUTTON(fw, i) == None)
4180 		{
4181 			continue;
4182 		}
4183 		if (ret_td->has_vt)
4184 		{
4185 			if (i & 1)
4186 			{
4187 				rbl += ret_td->layout.button_g[i].height;
4188 			}
4189 			else
4190 			{
4191 				lbl += ret_td->layout.button_g[i].height;
4192 			}
4193 		}
4194 		else
4195 		{
4196 			if (i & 1)
4197 			{
4198 				rbl += ret_td->layout.button_g[i].width;
4199 			}
4200 			else
4201 			{
4202 				lbl += ret_td->layout.button_g[i].width;
4203 			}
4204 		}
4205 	}
4206 
4207 	if (ret_td->has_an_upsidedown_rotation)
4208 	{
4209 		if (ret_td->has_vt)
4210 		{
4211 			ret_td->left_buttons_g.height = rbl;
4212 			ret_td->right_buttons_g.height = lbl;
4213 			ret_td->right_buttons_g.y = fw->boundary_width;
4214 			ret_td->right_buttons_g.x = ret_td->bar_g.x;
4215 			ret_td->left_buttons_g.y = ret_td->layout.title_g.y +
4216 				ret_td->layout.title_g.height;
4217 			ret_td->left_buttons_g.x = ret_td->bar_g.x;
4218 		}
4219 		else
4220 		{
4221 			ret_td->left_buttons_g.width = rbl;
4222 			ret_td->right_buttons_g.width = lbl;
4223 			ret_td->right_buttons_g.x = fw->boundary_width;
4224 			ret_td->right_buttons_g.y = ret_td->bar_g.y;
4225 			ret_td->left_buttons_g.x = ret_td->layout.title_g.x +
4226 				ret_td->layout.title_g.width;
4227 			ret_td->left_buttons_g.y = ret_td->bar_g.y;
4228 		}
4229 	}
4230 	else
4231 	{
4232 		if (ret_td->has_vt)
4233 		{
4234 			ret_td->left_buttons_g.height = lbl;
4235 			ret_td->right_buttons_g.height = rbl;
4236 			ret_td->left_buttons_g.y = fw->boundary_width;
4237 			ret_td->left_buttons_g.x = ret_td->bar_g.x;
4238 			ret_td->right_buttons_g.y = ret_td->layout.title_g.y +
4239 				ret_td->layout.title_g.height;
4240 			ret_td->right_buttons_g.x = ret_td->bar_g.x;
4241 		}
4242 		else
4243 		{
4244 			ret_td->left_buttons_g.width = lbl;
4245 			ret_td->right_buttons_g.width = rbl;
4246 			ret_td->left_buttons_g.x = fw->boundary_width;
4247 			ret_td->left_buttons_g.y = ret_td->bar_g.y;
4248 			ret_td->right_buttons_g.x = ret_td->layout.title_g.x +
4249 				ret_td->layout.title_g.width;
4250 			ret_td->right_buttons_g.y = ret_td->bar_g.y;
4251 		}
4252 	}
4253 
4254 	/* initialise flags */
4255 	border_get_titlebar_descr_state(
4256 		fw, pressed_parts, pressed_button, clear_parts, do_hilight,
4257 		&(ret_td->tbstate));
4258 
4259 	/* get the title string length and position
4260 	 * This is not in "tdd" (titlebar_draw_descr), because these are needed
4261 	 * to draw the buttons with UseTitleStyle */
4262 	just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
4263 	if (fw->visible_name != (char *)NULL)
4264 	{
4265 		ret_td->length = FlocaleTextWidth(
4266 			fw->title_font, fw->visible_name,
4267 			(ret_td->has_vt) ? -strlen(fw->visible_name) :
4268 			strlen(fw->visible_name));
4269 		if (ret_td->length > fw->title_length -
4270 		    2*MIN_WINDOW_TITLE_TEXT_OFFSET)
4271 		{
4272 			ret_td->length = fw->title_length -
4273 				2*MIN_WINDOW_TITLE_TEXT_OFFSET;
4274 			just = JUST_CENTER;
4275 		}
4276 		if (ret_td->length < 0)
4277 		{
4278 			ret_td->length = 0;
4279 		}
4280 	}
4281 	else
4282 	{
4283 		ret_td->length = 0;
4284 	}
4285 	if (ret_td->length == 0)
4286 	{
4287 		just = JUST_CENTER;
4288 	}
4289 	df = &TB_STATE(GetDecor(fw, titlebar))[ret_td->tbstate.tstate];
4290 	switch (just)
4291 	{
4292 	case JUST_LEFT:
4293 		is_start = 1;
4294 		/* fall through */
4295 	case JUST_RIGHT:
4296 		if (ret_td->has_an_upsidedown_rotation)
4297 		{
4298 			is_start = !is_start;
4299 		}
4300 		if (is_start)
4301 		{
4302 			if (WINDOW_TITLE_TEXT_OFFSET + ret_td->length <=
4303 			    fw->title_length)
4304 			{
4305 				ret_td->offset = WINDOW_TITLE_TEXT_OFFSET;
4306 			}
4307 			else
4308 			{
4309 				ret_td->offset =
4310 					fw->title_length - ret_td->length;
4311 			}
4312 		}
4313 		else
4314 		{
4315 			ret_td->offset = fw->title_length - ret_td->length -
4316 				WINDOW_TITLE_TEXT_OFFSET;
4317 		}
4318 		break;
4319 	case JUST_CENTER:
4320 	default:
4321 		ret_td->offset = (fw->title_length - ret_td->length) / 2;
4322 		break;
4323 	}
4324 
4325 	if (ret_td->offset < MIN_WINDOW_TITLE_TEXT_OFFSET)
4326 	{
4327 		ret_td->offset = MIN_WINDOW_TITLE_TEXT_OFFSET;
4328 	}
4329 
4330 	/* setup MultiPixmap */
4331 	border_mp_get_titlebar_descr(fw, ret_td, df);
4332 
4333 	/* determine the parts to draw */
4334 	draw_parts = border_get_tb_parts_to_draw(
4335 		fw, ret_td, old_g, new_g, force_draw_parts);
4336 
4337 	return draw_parts;
4338 }
4339 
4340 
border_draw_titlebar(common_decorations_type * cd,FvwmWindow * fw,window_parts pressed_parts,int pressed_button,window_parts force_draw_parts,clear_window_parts clear_parts,rectangle * old_g,rectangle * new_g,Bool do_hilight)4341 static void border_draw_titlebar(
4342 	common_decorations_type *cd, FvwmWindow *fw,
4343 	window_parts pressed_parts, int pressed_button,
4344 	window_parts force_draw_parts, clear_window_parts clear_parts,
4345 	rectangle *old_g, rectangle *new_g, Bool do_hilight)
4346 {
4347 	window_parts draw_parts;
4348 	titlebar_descr td;
4349 
4350 	if (!HAS_TITLE(fw))
4351 	{
4352 		/* just reset border states */
4353 		fw->decor_state.parts_drawn &= ~(PART_TITLE);
4354 		fw->decor_state.parts_lit &= ~(PART_TITLE);
4355 		fw->decor_state.parts_inverted &= ~(PART_TITLE);
4356 		fw->decor_state.buttons_drawn = 0;
4357 		fw->decor_state.buttons_lit = 0;
4358 		fw->decor_state.buttons_inverted = 0;
4359 		fw->decor_state.buttons_toggled = 0;
4360 		return;
4361 	}
4362 	memset(&td, 0, sizeof(td));
4363 	draw_parts = border_get_titlebar_descr(
4364 		cd, fw, pressed_parts, pressed_button, force_draw_parts,
4365 		clear_parts, old_g, new_g, do_hilight, &td);
4366 	if ((draw_parts & PART_TITLE) != PART_NONE ||
4367 	    (draw_parts & PART_BUTTONS) != PART_NONE)
4368 	{
4369 		/* set up UseTitleStyle Colorset */
4370 		border_setup_use_title_style(fw, &td);
4371 	}
4372 	if ((draw_parts & PART_TITLE) != PART_NONE)
4373 	{
4374 		border_draw_title(fw, &td);
4375 	}
4376 	if ((draw_parts & PART_BUTTONS) != PART_NONE)
4377 	{
4378 		border_draw_buttons(fw, &td);
4379 	}
4380 	border_free_bar_pixmaps(&(td.cd->dynamic_cd));
4381 
4382 	/* update the decor states */
4383 	fw->decor_state.parts_drawn |= draw_parts;
4384 	if (do_hilight)
4385 	{
4386 		fw->decor_state.parts_lit |= draw_parts;
4387 	}
4388 	else
4389 	{
4390 		fw->decor_state.parts_lit &= ~draw_parts;
4391 	}
4392 	fw->decor_state.parts_inverted &= ~draw_parts;
4393 	fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
4394 	if (draw_parts & PART_BUTTONS)
4395 	{
4396 		fw->decor_state.buttons_drawn |= td.tbstate.draw_bmask;
4397 		fw->decor_state.parts_lit = (do_hilight) ? ~0 : 0;
4398 		if (td.tbstate.pressed_bmask)
4399 		{
4400 			fw->decor_state.buttons_inverted =
4401 				td.tbstate.pressed_bmask;
4402 		}
4403 		else
4404 		{
4405 			fw->decor_state.buttons_inverted &=
4406 				~td.tbstate.draw_bmask;
4407 		}
4408 		fw->decor_state.buttons_toggled =
4409 			(fw->decor_state.buttons_toggled &
4410 			 ~td.tbstate.max_bmask) | td.tbstate.toggled_bmask;
4411 	}
4412 
4413 	return;
4414 }
4415 
4416 /*
4417  *
4418  * Redraws the windows borders
4419  *
4420  */
border_draw_border_parts(common_decorations_type * cd,FvwmWindow * fw,window_parts pressed_parts,window_parts force_draw_parts,clear_window_parts clear_parts,rectangle * old_g,rectangle * new_g,Bool do_hilight)4421 static void border_draw_border_parts(
4422 	common_decorations_type *cd, FvwmWindow *fw,
4423 	window_parts pressed_parts, window_parts force_draw_parts,
4424 	clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g,
4425 	Bool do_hilight)
4426 {
4427 	border_relief_descr br;
4428 	window_parts draw_parts;
4429 	Bool do_clear;
4430 
4431 	if (HAS_NO_BORDER(fw))
4432 	{
4433 		/* just reset border states */
4434 		fw->decor_state.parts_drawn &= ~(PART_FRAME | PART_HANDLES);
4435 		fw->decor_state.parts_lit &= ~(PART_FRAME | PART_HANDLES);
4436 		fw->decor_state.parts_inverted &= ~(PART_FRAME | PART_HANDLES);
4437 		return;
4438 	}
4439 	do_clear = (clear_parts & CLEAR_FRAME) ? True : False;
4440 	/* determine the parts to draw and the position to place them */
4441 	if (HAS_DEPRESSABLE_BORDER(fw))
4442 	{
4443 		pressed_parts &= PART_FRAME;
4444 	}
4445 	else
4446 	{
4447 		pressed_parts = PART_NONE;
4448 	}
4449 	force_draw_parts &= PART_FRAME;
4450 	memset(&br, 0, sizeof(br));
4451 	draw_parts = border_get_parts_and_pos_to_draw(
4452 		cd, fw, pressed_parts, force_draw_parts, old_g, new_g,
4453 		do_hilight, &br);
4454 	if ((draw_parts & PART_FRAME) != PART_NONE)
4455 	{
4456 		border_draw_all_border_parts(
4457 			cd, fw, &br, new_g, draw_parts, pressed_parts,
4458 			do_hilight, do_clear);
4459 	}
4460 	/* update the decor states */
4461 	fw->decor_state.parts_drawn |= draw_parts;
4462 	if (do_hilight)
4463 	{
4464 		fw->decor_state.parts_lit |= draw_parts;
4465 	}
4466 	else
4467 	{
4468 		fw->decor_state.parts_lit &= ~draw_parts;
4469 	}
4470 	fw->decor_state.parts_inverted &= ~draw_parts;
4471 	fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
4472 
4473 	return;
4474 }
4475 
4476 /* ---------------------------- interface functions ------------------------ */
4477 
border_get_border_style(FvwmWindow * fw,Bool has_focus)4478 DecorFace *border_get_border_style(
4479 	FvwmWindow *fw, Bool has_focus)
4480 {
4481 	DecorFace *df;
4482 
4483 	if (has_focus == True)
4484 	{
4485 		df = &(GetDecor(fw, BorderStyle.active));
4486 	}
4487 	else
4488 	{
4489 		df = &(GetDecor(fw, BorderStyle.inactive));
4490 	}
4491 
4492 	return df;
4493 }
4494 
border_is_using_border_style(FvwmWindow * fw,Bool has_focus)4495 int border_is_using_border_style(
4496 	FvwmWindow *fw, Bool has_focus)
4497 {
4498 	ButtonState bs;
4499 	int is_pressed;
4500 	int is_toggled;
4501 	int i;
4502 
4503 	/* title */
4504 	is_pressed = (FW_W_TITLE(fw) == PressedW);
4505 	bs = border_flags_to_button_state(is_pressed, has_focus, 0);
4506 	if (DFS_USE_BORDER_STYLE(TB_STATE(GetDecor(fw, titlebar))[bs].style))
4507 	{
4508 		return 1;
4509 	}
4510 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4511 	{
4512 		if (FW_W_BUTTON(fw, i) == None)
4513 		{
4514 			continue;
4515 		}
4516 		is_pressed = (FW_W_BUTTON(fw, i) == PressedW);
4517 		is_toggled = (is_button_toggled(fw, i) == True);
4518 		bs = border_flags_to_button_state(
4519 			is_pressed, (has_focus == True), is_toggled);
4520 		if (DFS_USE_BORDER_STYLE(
4521 			    TB_STATE(GetDecor(fw, buttons[i]))[bs].style))
4522 		{
4523 			return 1;
4524 		}
4525 	}
4526 
4527 	return 0;
4528 }
4529 
border_context_to_parts(int context)4530 int border_context_to_parts(
4531 	int context)
4532 {
4533 	if (context == C_FRAME || context == C_SIDEBAR ||
4534 	    context == (C_FRAME | C_SIDEBAR))
4535 	{
4536 		return PART_FRAME;
4537 	}
4538 	else if (context == C_F_TOPLEFT)
4539 	{
4540 		return PART_BORDER_NW;
4541 	}
4542 	else if (context == C_F_TOPRIGHT)
4543 	{
4544 		return PART_BORDER_NE;
4545 	}
4546 	else if (context == C_F_BOTTOMLEFT)
4547 	{
4548 		return PART_BORDER_SW;
4549 	}
4550 	else if (context == C_F_BOTTOMRIGHT)
4551 	{
4552 		return PART_BORDER_SE;
4553 	}
4554 	else if (context == C_SB_LEFT)
4555 	{
4556 		return PART_BORDER_W;
4557 	}
4558 	else if (context == C_SB_RIGHT)
4559 	{
4560 		return PART_BORDER_E;
4561 	}
4562 	else if (context == C_SB_TOP)
4563 	{
4564 		return PART_BORDER_N;
4565 	}
4566 	else if (context == C_SB_BOTTOM)
4567 	{
4568 		return PART_BORDER_S;
4569 	}
4570 	else if (context == C_TITLE)
4571 	{
4572 		return PART_TITLE;
4573 	}
4574 	else if (context & (C_LALL | C_RALL))
4575 	{
4576 		return PART_BUTTONS;
4577 	}
4578 
4579 	return PART_NONE;
4580 }
4581 
border_get_part_geometry(FvwmWindow * fw,window_parts part,rectangle * sidebar_g,rectangle * ret_g,Window * ret_w)4582 void border_get_part_geometry(
4583 	FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
4584 	rectangle *ret_g, Window *ret_w)
4585 {
4586 	int bw;
4587 
4588 	bw = fw->boundary_width;
4589 	/* ret_g->x and ret->y is just an offset relatively to the w,
4590 	 * maybe we can take the relief in account? */
4591 	switch (part)
4592 	{
4593 	case PART_BORDER_N:
4594 		ret_g->x = sidebar_g->x;
4595 		ret_g->y = 0;
4596 		*ret_w = FW_W_SIDE(fw, 0);
4597 		break;
4598 	case PART_BORDER_E:
4599 		ret_g->x = 2 * sidebar_g->x + sidebar_g->width - bw;
4600 		ret_g->y = sidebar_g->y;
4601 		*ret_w = FW_W_SIDE(fw, 1);
4602 		break;
4603 	case PART_BORDER_S:
4604 		ret_g->x = sidebar_g->x;
4605 		ret_g->y = 2 * sidebar_g->y + sidebar_g->height - bw;
4606 		*ret_w = FW_W_SIDE(fw, 2);
4607 		break;
4608 	case PART_BORDER_W:
4609 		ret_g->x = 0;
4610 		ret_g->y = sidebar_g->y;
4611 		*ret_w = FW_W_SIDE(fw, 3);
4612 		break;
4613 	case PART_BORDER_NW:
4614 		ret_g->x = 0;
4615 		ret_g->y = 0;
4616 		*ret_w = FW_W_CORNER(fw, 0);
4617 		break;
4618 	case PART_BORDER_NE:
4619 		ret_g->x = sidebar_g->x + sidebar_g->width;
4620 		ret_g->y = 0;
4621 		*ret_w = FW_W_CORNER(fw, 1);
4622 		break;
4623 	case PART_BORDER_SW:
4624 		ret_g->x = 0;
4625 		ret_g->y = sidebar_g->y + sidebar_g->height;
4626 		*ret_w = FW_W_CORNER(fw, 2);
4627 		break;
4628 	case PART_BORDER_SE:
4629 		ret_g->x = sidebar_g->x + sidebar_g->width;
4630 		ret_g->y = sidebar_g->y + sidebar_g->height;
4631 		*ret_w = FW_W_CORNER(fw, 3);
4632 		break;
4633 	default:
4634 		break;
4635 	}
4636 
4637 	switch (part)
4638 	{
4639 	case PART_BORDER_N:
4640 	case PART_BORDER_S:
4641 		ret_g->width = sidebar_g->width;
4642 		ret_g->height = bw;
4643 		break;
4644 	case PART_BORDER_E:
4645 	case PART_BORDER_W:
4646 		ret_g->width = bw;
4647 		ret_g->height = sidebar_g->height;
4648 		break;
4649 	case PART_BORDER_NW:
4650 	case PART_BORDER_NE:
4651 	case PART_BORDER_SW:
4652 	case PART_BORDER_SE:
4653 		ret_g->width = sidebar_g->x;
4654 		ret_g->height = sidebar_g->y;
4655 		break;
4656 	default:
4657 		return;
4658 	}
4659 
4660 	return;
4661 }
4662 
get_button_number(int context)4663 int get_button_number(int context)
4664 {
4665 	int i;
4666 
4667 	for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++)
4668 	{
4669 		if (context & (C_L1 << i))
4670 		{
4671 			return i;
4672 		}
4673 	}
4674 
4675 	return -1;
4676 }
4677 
border_draw_decorations(FvwmWindow * fw,window_parts draw_parts,Bool has_focus,Bool do_force,clear_window_parts clear_parts,rectangle * old_g,rectangle * new_g)4678 void border_draw_decorations(
4679 	FvwmWindow *fw, window_parts draw_parts, Bool has_focus, Bool do_force,
4680 	clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g)
4681 {
4682 	common_decorations_type cd;
4683 	Bool do_redraw_titlebar = False;
4684 	window_parts pressed_parts;
4685 	window_parts force_parts;
4686 	int context;
4687 	int item;
4688 
4689 	if (fw == NULL)
4690 	{
4691 		return;
4692 	}
4693 	if (WAS_NEVER_DRAWN(fw))
4694 	{
4695 		/* force drawing everything */
4696 		do_force = True;
4697 		draw_parts = PART_ALL;
4698 		SET_WAS_NEVER_DRAWN(fw, 0);
4699 	}
4700 	memset(&cd, 0, sizeof(cd));
4701 
4702 	/* can't compare with True here, old code calls this with value "2" */
4703 	if (do_force != False)
4704 	{
4705 		force_parts = draw_parts;
4706 	}
4707 	else
4708 	{
4709 		force_parts = PART_NONE;
4710 	}
4711 	if (has_focus)
4712 	{
4713 		/* don't re-draw just for kicks */
4714 		if (Scr.Hilite != fw && Scr.Hilite != NULL)
4715 		{
4716 			FvwmWindow *t = Scr.Hilite;
4717 
4718 			Scr.Hilite = NULL;
4719 			/* make sure that the previously highlighted
4720 			 * window got unhighlighted */
4721 			border_draw_decorations(
4722 				t, PART_ALL, False, True, CLEAR_ALL, NULL,
4723 				NULL);
4724 		}
4725 		Scr.Hilite = fw;
4726 	}
4727 	else if (fw == Scr.Hilite)
4728 	{
4729 		Scr.Hilite = NULL;
4730 	}
4731 
4732 	if (IS_ICONIFIED(fw))
4733 	{
4734 		DrawIconWindow(fw, True, True, True, False, NULL);
4735 		return;
4736 	}
4737 	/* calculate some values and flags */
4738 	if ((draw_parts & PART_TITLEBAR) && HAS_TITLE(fw))
4739 	{
4740 		do_redraw_titlebar = True;
4741 	}
4742 	get_common_decorations(
4743 		&cd, fw, draw_parts, has_focus, False, do_redraw_titlebar);
4744 	/* redraw */
4745 	context = frame_window_id_to_context(fw, PressedW, &item);
4746 	if ((context & (C_LALL | C_RALL)) == 0)
4747 	{
4748 		item = -1;
4749 	}
4750 	pressed_parts = border_context_to_parts(context);
4751 	if (new_g == NULL)
4752 	{
4753 		new_g = &fw->g.frame;
4754 	}
4755 	if (do_redraw_titlebar)
4756 	{
4757 		border_draw_titlebar(
4758 			&cd, fw, pressed_parts & PART_TITLEBAR, item,
4759 			force_parts & PART_TITLEBAR,
4760 			clear_parts, old_g, new_g, has_focus);
4761 	}
4762 	if (draw_parts & PART_FRAME)
4763 	{
4764 		Pixmap save_pix = cd.dynamic_cd.frame_pixmap;
4765 
4766 		memset(&cd, 0, sizeof(cd));
4767 		get_common_decorations(
4768 			&cd, fw, draw_parts, has_focus, True, True);
4769 		cd.dynamic_cd.frame_pixmap = save_pix;
4770 		border_draw_border_parts(
4771 			&cd, fw,
4772 			(pressed_parts & (PART_FRAME | PART_HANDLES)),
4773 			(force_parts & (PART_FRAME | PART_HANDLES)),
4774 			clear_parts, old_g, new_g, has_focus);
4775 	}
4776 	if (cd.dynamic_cd.frame_pixmap != None)
4777 	{
4778 		XFreePixmap(dpy, cd.dynamic_cd.frame_pixmap);
4779 	}
4780 	return;
4781 }
4782 
border_undraw_decorations(FvwmWindow * fw)4783 void border_undraw_decorations(
4784 	FvwmWindow *fw)
4785 {
4786 	memset(&fw->decor_state, 0, sizeof(fw->decor_state));
4787 
4788 	return;
4789 }
4790 
4791 /*
4792  *
4793  *  redraw the decoration when style change
4794  *
4795  */
border_redraw_decorations(FvwmWindow * fw)4796 void border_redraw_decorations(
4797 	FvwmWindow *fw)
4798 {
4799 	FvwmWindow *u = Scr.Hilite;
4800 
4801 	/* domivogt (6-Jun-2000): Don't check if the window is visible here.
4802 	 * If we do, some updates are not applied and when the window becomes
4803 	 * visible again, the X Server may not redraw the window. */
4804 	border_draw_decorations(
4805 		fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL);
4806 	Scr.Hilite = u;
4807 
4808 	return;
4809 }
4810 
4811 /*
4812  *
4813  *  get the the root transparent parts of the decoration
4814  *
4815  */
border_get_transparent_decorations_part(FvwmWindow * fw)4816 unsigned int border_get_transparent_decorations_part(FvwmWindow *fw)
4817 {
4818 	DecorFace *df,*tdf;
4819 	unsigned int draw_parts = PART_NONE;
4820 	int i;
4821 	window_parts pressed_parts;
4822 	int context;
4823 	int item;
4824 	border_titlebar_state tbstate;
4825 	Bool title_use_borderstyle = False;
4826 	Bool buttons_use_borderstyle = False;
4827 	Bool buttons_use_titlestyle = False;
4828 
4829 	context = frame_window_id_to_context(fw, PressedW, &item);
4830 	if ((context & (C_LALL | C_RALL)) == 0)
4831 	{
4832 		item = -1;
4833 	}
4834 	pressed_parts = border_context_to_parts(context);
4835 
4836 	memset(&tbstate, 0, sizeof(tbstate));
4837 	border_get_titlebar_descr_state(
4838 		fw, pressed_parts & PART_TITLEBAR, item,
4839 		CLEAR_ALL, (Scr.Hilite == fw), &tbstate);
4840 
4841 	for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4842 	{
4843 		df = &TB_STATE(GetDecor(fw, buttons[i]))[tbstate.bstate[i]];
4844 
4845 		if (DFS_USE_TITLE_STYLE(df->style))
4846 		{
4847 			buttons_use_titlestyle = True;
4848 		}
4849 		if (DFS_USE_BORDER_STYLE(df->style))
4850 		{
4851 			buttons_use_borderstyle = True;
4852 		}
4853 		for(tdf = df; tdf != NULL; tdf = tdf->next)
4854 		{
4855 			if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
4856 			    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
4857 			{
4858 				draw_parts |= PART_BUTTONS;
4859 				break;
4860 			}
4861 		}
4862 	}
4863 
4864 	df = &TB_STATE(GetDecor(fw, titlebar))[tbstate.tstate];
4865 	if (DFS_USE_BORDER_STYLE(df->style))
4866 	{
4867 		title_use_borderstyle = True;
4868 	}
4869 	for(tdf = df; tdf != NULL; tdf = tdf->next)
4870 	{
4871 		if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
4872 		    CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
4873 		{
4874 			draw_parts |= PART_TITLE;
4875 			break;
4876 		}
4877 		else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
4878 		{
4879 			int i;
4880 
4881 			for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
4882 			{
4883 				if (CSET_IS_TRANSPARENT_ROOT(
4884 					tdf->u.mp.acs[i].cs))
4885 				{
4886 					draw_parts |= PART_TITLE;
4887 					break;
4888 				}
4889 			}
4890 		}
4891 	}
4892 
4893 	df = border_get_border_style(fw, (Scr.Hilite == fw));
4894 	if (DFS_FACE_TYPE(df->style) == ColorsetButton &&
4895 	    CSET_IS_TRANSPARENT_ROOT(df->u.acs.cs))
4896 	{
4897 		draw_parts |= PART_FRAME|PART_HANDLES;
4898 	}
4899 	if (draw_parts & PART_FRAME)
4900 	{
4901 		if (title_use_borderstyle)
4902 		{
4903 			draw_parts |= PART_TITLE;
4904 		}
4905 		if (buttons_use_borderstyle)
4906 		{
4907 			draw_parts |= PART_BUTTONS;
4908 		}
4909 	}
4910 	if ((draw_parts & PART_TITLE) && buttons_use_titlestyle)
4911 	{
4912 		draw_parts |= PART_BUTTONS;
4913 	}
4914 #if 0
4915 	fprintf(stderr,"Transparant Part: %u\n", draw_parts);
4916 #endif
4917 	return draw_parts;
4918 }
4919 
4920 /* ---------------------------- builtin commands --------------------------- */
4921 
4922 /*
4923  *
4924  *  Sets the allowed button states
4925  *
4926  */
CMD_ButtonState(F_CMD_ARGS)4927 void CMD_ButtonState(F_CMD_ARGS)
4928 {
4929 	char *token;
4930 
4931 	while ((token = PeekToken(action, &action)))
4932 	{
4933 		static char first = True;
4934 		if (!token && first)
4935 		{
4936 			Scr.gs.use_active_down_buttons =
4937 				DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
4938 			Scr.gs.use_inactive_buttons =
4939 				DEFAULT_USE_INACTIVE_BUTTONS;
4940 			Scr.gs.use_inactive_down_buttons =
4941 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
4942 			return;
4943 		}
4944 		first = False;
4945 		if (StrEquals("activedown", token))
4946 		{
4947 			Scr.gs.use_active_down_buttons = ParseToggleArgument(
4948 				action, &action,
4949 				DEFAULT_USE_ACTIVE_DOWN_BUTTONS, True);
4950 		}
4951 		else if (StrEquals("inactive", token))
4952 		{
4953 			Scr.gs.use_inactive_buttons = ParseToggleArgument(
4954 				action, &action,
4955 				DEFAULT_USE_INACTIVE_BUTTONS, True);
4956 		}
4957 		else if (StrEquals("inactivedown", token))
4958 		{
4959 			Scr.gs.use_inactive_down_buttons = ParseToggleArgument(
4960 				action, &action,
4961 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS, True);
4962 		}
4963 		else
4964 		{
4965 			Scr.gs.use_active_down_buttons =
4966 				DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
4967 			Scr.gs.use_inactive_buttons =
4968 				DEFAULT_USE_INACTIVE_BUTTONS;
4969 			Scr.gs.use_inactive_down_buttons =
4970 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
4971 			fvwm_debug(__func__,
4972 				   "Unknown button state %s", token);
4973 			return;
4974 		}
4975 	}
4976 
4977 	return;
4978 }
4979 
4980 /*
4981  *
4982  *  Sets the border style (veliaa@rpi.edu)
4983  *
4984  */
CMD_BorderStyle(F_CMD_ARGS)4985 void CMD_BorderStyle(F_CMD_ARGS)
4986 {
4987 	char *parm;
4988 	char *prev;
4989 	FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
4990 
4991 	Scr.flags.do_need_window_update = 1;
4992 	decor->flags.has_changed = 1;
4993 	for (prev = action; (parm = PeekToken(action, &action)); prev = action)
4994 	{
4995 		if (StrEquals(parm, "active") || StrEquals(parm, "inactive"))
4996 		{
4997 			int len;
4998 			char *end, *tmp;
4999 			DecorFace tmpdf, *df;
5000 
5001 			memset(&tmpdf.style, 0, sizeof(tmpdf.style));
5002 			DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
5003 			tmpdf.next = NULL;
5004 			if (FMiniIconsSupported)
5005 			{
5006 				tmpdf.u.p = NULL;
5007 			}
5008 			if (StrEquals(parm,"active"))
5009 			{
5010 				df = &decor->BorderStyle.active;
5011 			}
5012 			else
5013 			{
5014 				df = &decor->BorderStyle.inactive;
5015 			}
5016 			df->flags.has_changed = 1;
5017 			while (isspace(*action))
5018 			{
5019 				++action;
5020 			}
5021 			if (*action != '(')
5022 			{
5023 				if (!*action)
5024 				{
5025 					fvwm_debug(__func__,
5026 						   "error in %s border"
5027 						   " specification", parm);
5028 					return;
5029 				}
5030 				while (isspace(*action))
5031 				{
5032 					++action;
5033 				}
5034 				if (ReadDecorFace(action, &tmpdf,-1,True))
5035 				{
5036 					FreeDecorFace(dpy, df);
5037 					*df = tmpdf;
5038 				}
5039 				break;
5040 			}
5041 			end = strchr(++action, ')');
5042 			if (!end)
5043 			{
5044 				fvwm_debug(__func__,
5045 					   "error in %s border specification",
5046 					   parm);
5047 				return;
5048 			}
5049 			len = end - action + 1;
5050 			/* TA:  FIXME xasprintf */
5051 			tmp = fxmalloc(len);
5052 			strncpy(tmp, action, len - 1);
5053 			tmp[len - 1] = 0;
5054 			ReadDecorFace(tmp, df,-1,True);
5055 			free(tmp);
5056 			action = end + 1;
5057 		}
5058 		else if (strcmp(parm,"--")==0)
5059 		{
5060 			if (ReadDecorFace(
5061 				    prev, &decor->BorderStyle.active,-1,True))
5062 			{
5063 				ReadDecorFace(
5064 					prev, &decor->BorderStyle.inactive, -1,
5065 					False);
5066 			}
5067 			decor->BorderStyle.active.flags.has_changed = 1;
5068 			decor->BorderStyle.inactive.flags.has_changed = 1;
5069 			break;
5070 		}
5071 		else
5072 		{
5073 			DecorFace tmpdf;
5074 			memset(&tmpdf.style, 0, sizeof(tmpdf.style));
5075 			DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
5076 			tmpdf.next = NULL;
5077 			if (FMiniIconsSupported)
5078 			{
5079 				tmpdf.u.p = NULL;
5080 			}
5081 			if (ReadDecorFace(prev, &tmpdf,-1,True))
5082 			{
5083 				FreeDecorFace(dpy,&decor->BorderStyle.active);
5084 				decor->BorderStyle.active = tmpdf;
5085 				ReadDecorFace(
5086 					prev, &decor->BorderStyle.inactive, -1,
5087 					False);
5088 				decor->BorderStyle.active.flags.has_changed = 1;
5089 				decor->BorderStyle.inactive.flags.has_changed =
5090 					1;
5091 			}
5092 			break;
5093 		}
5094 	}
5095 
5096 	return;
5097 }
5098