Fix ExplainWindowPlacement when using "NoUSPosition" style.
[fvwm.git] / fvwm / borders.c
blobe88352f6a013511b51fb83a116ce84c23dc2da91
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.
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.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* IMPORTANT NOTE:
27 * The functions in this module *must not* assume that the geometries in the
28 * FvwmWindow structure reflect the desired geometry of the window or its
29 * parts. While the window is resized or shaded, they may hold the old
30 * geometry instead of the new one (but you can not rely on this). Therefore,
31 * these geometries must not be accessed directly or indirectly (by the
32 * functions from geometry,c). Use the geometries that are passed in via
33 * structure pointers, e.d. "td".
36 /* ---------------------------- included header files ---------------------- */
38 #include "config.h"
40 #include <stdio.h>
42 #include "libs/fvwmlib.h"
43 #include "libs/Parse.h"
44 #include "libs/Graphics.h"
45 #include "libs/Picture.h"
46 #include "libs/PictureGraphics.h"
47 #include "libs/FRenderInit.h"
48 #include "libs/charmap.h"
49 #include "libs/wcontext.h"
50 #include "fvwm.h"
51 #include "execcontext.h"
52 #include "externs.h"
53 #include "misc.h"
54 #include "screen.h"
55 #include "geometry.h"
56 #include "borders.h"
57 #include "builtins.h"
58 #include "icons.h"
59 #include "frame.h"
61 /* ---------------------------- local definitions -------------------------- */
63 /* ---------------------------- local macros ------------------------------- */
65 #define SWAP_ARGS(f,a1,a2) (f)?(a2):(a1),(f)?(a1):(a2)
67 /* ---------------------------- imports ------------------------------------ */
69 extern Window PressedW;
71 /* ---------------------------- included code files ------------------------ */
73 /* ---------------------------- local types -------------------------------- */
75 typedef struct
77 struct
79 unsigned use_pixmap : 1;
80 } flags;
81 Pixel pixel;
82 struct
84 Pixmap p;
85 Pixmap shape;
86 Pixmap alpha;
87 int depth;
88 FvwmRenderAttributes fra;
89 rectangle g;
90 int stretch_w;
91 int stretch_h;
92 struct
94 unsigned is_tiled : 1;
95 unsigned is_stretched : 1;
96 } flags;
97 } pixmap;
98 } pixmap_background_type;
100 typedef struct
102 Pixmap p;
103 FvwmPicture *mp_created_pic;
104 int cs;
105 FvwmPicture *mp_pic;
106 int mp_part;
107 Bool created;
108 } bar_pixmap;
110 typedef struct
112 int count;
113 bar_pixmap *bps;
114 } bar_bs_pixmaps; /* for UseTitleStyle & Colorset */
116 typedef struct
118 Pixmap frame_pixmap;
119 bar_bs_pixmaps bar_pixmaps[BS_MaxButtonState];
120 } dynamic_common_decorations;
122 typedef struct
124 int relief_width;
125 GC relief_gc;
126 GC shadow_gc;
127 Pixel fore_color;
128 Pixel back_color;
129 int cs;
130 int border_cs; /* for UseBorderStyle */
131 int bg_border_cs; /* for UseBorderStyle */
132 Pixmap back_pixmap;
133 XSetWindowAttributes attributes;
134 unsigned long valuemask;
135 Pixmap texture_pixmap;
136 int texture_pixmap_width;
137 int texture_pixmap_height;
138 XSetWindowAttributes notex_attributes;
139 unsigned long notex_valuemask;
140 dynamic_common_decorations dynamic_cd;
141 } common_decorations_type;
143 typedef struct
145 GC relief;
146 GC shadow;
147 GC transparent;
148 } draw_border_gcs;
150 typedef struct
152 int offset_tl;
153 int offset_br;
154 int thickness;
155 int length;
156 unsigned has_x_marks : 1;
157 unsigned has_y_marks : 1;
158 } border_marks_descr;
160 typedef struct
162 int w_dout;
163 int w_hiout;
164 int w_trout;
165 int w_c;
166 int w_trin;
167 int w_shin;
168 int w_din;
169 int sum;
170 int trim;
171 unsigned is_flat : 1;
172 } border_relief_size_descr;
174 typedef struct
176 rectangle sidebar_g;
177 border_relief_size_descr relief;
178 border_marks_descr marks;
179 draw_border_gcs gcs;
180 } border_relief_descr;
182 typedef struct
184 unsigned pressed_bmask : NUMBER_OF_TITLE_BUTTONS;
185 unsigned lit_bmask : NUMBER_OF_TITLE_BUTTONS;
186 unsigned toggled_bmask : NUMBER_OF_TITLE_BUTTONS;
187 unsigned clear_bmask : NUMBER_OF_TITLE_BUTTONS;
188 unsigned draw_bmask : NUMBER_OF_TITLE_BUTTONS;
189 unsigned max_bmask : NUMBER_OF_TITLE_BUTTONS;
190 ButtonState bstate[NUMBER_OF_TITLE_BUTTONS];
191 unsigned is_title_pressed : 1;
192 unsigned is_title_lit : 1;
193 unsigned do_clear_title : 1;
194 ButtonState tstate;
195 } border_titlebar_state;
197 typedef struct
199 GC rgc;
200 GC sgc;
201 FlocaleWinString fstr;
202 DecorFaceStyle *tstyle;
203 DecorFace *df;
204 unsigned is_toggled : 1;
205 } title_draw_descr;
207 typedef struct
209 common_decorations_type *cd;
210 rectangle frame_g;
211 rectangle bar_g; /* titlebar geo vs the frame */
212 rectangle left_buttons_g; /* vs the frame */
213 rectangle right_buttons_g; /* vs the frame */
214 frame_title_layout_t layout;
215 frame_title_layout_t old_layout;
216 border_titlebar_state tbstate;
217 int length; /* text */
218 int offset; /* text offset */
219 /* MultiPixmap Geometries */
220 rectangle under_text_g; /* vs the titlebar */
221 rectangle left_main_g; /* vs the titlebar */
222 rectangle right_main_g; /* vs the titlebar */
223 rectangle full_left_main_g; /* vs the frame */
224 rectangle full_right_main_g; /* vs the frame */
225 int left_end_length;
226 int left_of_text_length;
227 int right_end_length;
228 int right_of_text_length;
229 rotation_t draw_rotation;
230 rotation_t restore_rotation;
231 unsigned td_is_rotated : 1;
232 unsigned has_been_saved : 1;
233 unsigned has_vt : 1; /* vertical title ? */
234 unsigned has_an_upsidedown_rotation : 1; /* 270 || 180 */
235 } titlebar_descr;
237 /* ---------------------------- forward declarations ----------------------- */
238 /* forward declarations are not so good */
240 /* for grouping titlebar_descr computation */
241 static void border_rotate_titlebar_descr(FvwmWindow *fw, titlebar_descr *td);
243 /* for grouping the MultiPixmap stuff */
244 static Bool border_mp_get_use_title_style_parts_and_geometry(
245 titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
246 unsigned short sf, int is_left, rectangle *g, int *part);
248 /* ---------------------------- local variables ---------------------------- */
250 static const char ulgc[] = { 1, 0, 0, 0x7f, 2, 1, 1 };
251 static const char brgc[] = { 1, 1, 2, 0x7f, 0, 0, 3 };
253 /* ---------------------------- exported variables (globals) --------------- */
255 XGCValues Globalgcv;
256 unsigned long Globalgcm;
258 /* ---------------------------- local functions ---------------------------- */
260 static Bool is_button_toggled(
261 FvwmWindow *fw, int button)
263 mwm_flags mf;
265 if (!HAS_MWM_BUTTONS(fw))
267 return False;
269 mf = TB_MWM_DECOR_FLAGS(GetDecor(fw, buttons[button]));
270 if ((mf & MWM_DECOR_MAXIMIZE) && IS_MAXIMIZED(fw))
272 return True;
274 if ((mf & MWM_DECOR_SHADE) && IS_SHADED(fw))
276 return True;
278 if ((mf & MWM_DECOR_STICK) &&
279 (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
281 return True;
283 if (TB_FLAGS(fw->decor->buttons[button]).has_layer &&
284 fw->layer == TB_LAYER(fw->decor->buttons[button]))
286 return True;
289 return False;
293 /* rules to get button state */
294 static ButtonState border_flags_to_button_state(
295 int is_pressed, int is_lit, int is_toggled)
297 if (!is_lit && Scr.gs.use_inactive_buttons)
299 if (is_pressed && Scr.gs.use_inactive_down_buttons)
301 return (is_toggled) ?
302 BS_ToggledInactiveDown : BS_InactiveDown;
304 else
306 return (is_toggled) ?
307 BS_ToggledInactiveUp : BS_InactiveUp;
310 else
312 if (is_pressed && Scr.gs.use_active_down_buttons)
314 return (is_toggled) ?
315 BS_ToggledActiveDown : BS_ActiveDown;
317 else
319 return (is_toggled) ?
320 BS_ToggledActiveUp : BS_ActiveUp;
325 static void get_common_decorations(
326 common_decorations_type *cd, FvwmWindow *t,
327 window_parts draw_parts, Bool has_focus, Bool is_border,
328 Bool do_change_gcs)
330 DecorFace *df;
331 color_quad *draw_colors;
333 df = border_get_border_style(t, has_focus);
334 cd->bg_border_cs = -1;
335 cd->cs = -1;
336 if (has_focus)
338 /* are we using textured borders? */
339 if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
340 GetDecor(t, BorderStyle.active.u.p->depth) == Pdepth)
342 cd->texture_pixmap = GetDecor(
343 t, BorderStyle.active.u.p->picture);
344 cd->texture_pixmap_width = GetDecor(
345 t, BorderStyle.active.u.p->width);
346 cd->texture_pixmap_height = GetDecor(
347 t, BorderStyle.active.u.p->height);
349 else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
351 cd->bg_border_cs = GetDecor(
352 t, BorderStyle.active.u.acs.cs);
354 cd->back_pixmap = Scr.gray_pixmap;
355 if (is_border)
357 draw_colors = &(t->border_hicolors);
358 cd->cs = t->border_cs_hi;
360 else
362 draw_colors = &(t->hicolors);
363 cd->cs = t->cs_hi;
366 else
368 if (DFS_FACE_TYPE(df->style) == TiledPixmapButton &&
369 GetDecor(t, BorderStyle.inactive.u.p->depth) == Pdepth)
371 cd->texture_pixmap = GetDecor(
372 t, BorderStyle.inactive.u.p->picture);
373 cd->texture_pixmap_width = GetDecor(
374 t, BorderStyle.inactive.u.p->width);
375 cd->texture_pixmap_height = GetDecor(
376 t, BorderStyle.inactive.u.p->height);
378 else if (DFS_FACE_TYPE(df->style) == ColorsetButton)
380 cd->bg_border_cs = GetDecor(
381 t, BorderStyle.inactive.u.acs.cs);
383 if (IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t))
385 cd->back_pixmap = Scr.sticky_gray_pixmap;
387 else
389 cd->back_pixmap = Scr.light_gray_pixmap;
391 if (is_border)
393 draw_colors = &(t->border_colors);
394 cd->cs = t->border_cs;
396 else
398 draw_colors = &(t->colors);
399 cd->cs = t->cs;
402 cd->fore_color = draw_colors->fore;
403 cd->back_color = draw_colors->back;
404 if (do_change_gcs)
406 Globalgcv.foreground = draw_colors->hilight;
407 Globalgcm = GCForeground;
408 XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv);
409 Globalgcv.foreground = draw_colors->shadow;
410 XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv);
411 cd->relief_gc = Scr.ScratchGC1;
412 cd->shadow_gc = Scr.ScratchGC2;
415 /* MWMBorder style means thin 3d effects */
416 cd->relief_width = (HAS_MWM_BORDER(t) ? 1 : 2);
418 if (cd->texture_pixmap)
420 cd->attributes.background_pixmap = cd->texture_pixmap;
421 cd->valuemask = CWBackPixmap;
423 else
425 if (Pdepth < 2)
427 cd->attributes.background_pixmap = cd->back_pixmap;
428 cd->valuemask = CWBackPixmap;
430 else
432 cd->attributes.background_pixel = cd->back_color;
433 cd->valuemask = CWBackPixel;
436 if (Pdepth < 2)
438 cd->notex_attributes.background_pixmap = cd->back_pixmap;
439 cd->notex_valuemask = CWBackPixmap;
441 else
443 cd->notex_attributes.background_pixel = cd->back_color;
444 cd->notex_valuemask = CWBackPixel;
447 return;
450 static window_parts border_get_changed_border_parts(
451 FvwmWindow *fw, rectangle *old_sidebar_g, rectangle *new_sidebar_g,
452 int cs)
454 window_parts changed_parts;
456 changed_parts = PART_NONE;
457 if (!CSET_IS_TRANSPARENT_PR(cs) && CSET_HAS_PIXMAP(cs) &&
458 (old_sidebar_g->x != new_sidebar_g->x ||
459 old_sidebar_g->y != new_sidebar_g->y ||
460 old_sidebar_g->width != new_sidebar_g->width ||
461 old_sidebar_g->height != new_sidebar_g->height))
463 /* optimizable? */
464 changed_parts |= PART_FRAME;
465 return changed_parts;
467 if (old_sidebar_g->x != new_sidebar_g->x)
469 changed_parts |= (PART_FRAME & (~PART_BORDER_W));
471 if (old_sidebar_g->y != new_sidebar_g->y)
473 changed_parts |= (PART_FRAME & (~PART_BORDER_N));
475 if (old_sidebar_g->width != new_sidebar_g->width)
477 changed_parts |=
478 PART_BORDER_N | PART_BORDER_S;
479 if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
480 TiledPixmapButton)
482 changed_parts |=
483 PART_BORDER_NE | PART_BORDER_E | PART_BORDER_SE;
486 if (old_sidebar_g->height != new_sidebar_g->height)
488 changed_parts |=
489 PART_BORDER_W | PART_BORDER_E;
490 if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) ==
491 TiledPixmapButton)
493 changed_parts |=
494 PART_BORDER_SW | PART_BORDER_S | PART_BORDER_SE;
498 return changed_parts;
501 static int border_get_parts_and_pos_to_draw(
502 common_decorations_type *cd, FvwmWindow *fw,
503 window_parts pressed_parts, window_parts force_draw_parts,
504 rectangle *old_g, rectangle *new_g, Bool do_hilight,
505 border_relief_descr *br)
507 window_parts draw_parts;
508 window_parts parts_to_light;
509 rectangle sidebar_g_old;
510 DecorFaceStyle *borderstyle;
511 Bool has_x_marks;
512 Bool has_x_marks_old;
513 Bool has_y_marks;
514 Bool has_y_marks_old;
515 int cs = cd->bg_border_cs;
517 draw_parts = 0;
518 borderstyle = (do_hilight) ?
519 &GetDecor(fw, BorderStyle.active.style) :
520 &GetDecor(fw, BorderStyle.inactive.style);
521 frame_get_sidebar_geometry(
522 fw, borderstyle, new_g, &br->sidebar_g, &has_x_marks,
523 &has_y_marks);
524 if (has_x_marks == True)
526 draw_parts |= PART_X_HANDLES;
527 br->marks.has_x_marks = 1;
529 else
531 br->marks.has_x_marks = 0;
533 if (has_y_marks == True)
535 draw_parts |= PART_Y_HANDLES;
536 br->marks.has_y_marks = 1;
538 else
540 br->marks.has_y_marks = 0;
542 draw_parts |= (pressed_parts ^ fw->decor_state.parts_inverted);
543 parts_to_light = (do_hilight == True) ? PART_FRAME : PART_NONE;
544 draw_parts |= (parts_to_light ^ fw->decor_state.parts_lit);
545 draw_parts |= (~(fw->decor_state.parts_drawn) & PART_FRAME);
546 draw_parts |= force_draw_parts;
547 if (old_g == NULL)
549 old_g = &fw->g.frame;
551 if ((draw_parts & PART_FRAME) == PART_FRAME)
553 draw_parts |= PART_FRAME;
554 return draw_parts;
556 frame_get_sidebar_geometry(
557 fw, borderstyle, old_g, &sidebar_g_old, &has_x_marks_old,
558 &has_y_marks_old);
559 if (has_x_marks_old != has_x_marks)
561 draw_parts |= (PART_FRAME & (~(PART_BORDER_N | PART_BORDER_S)));
563 if (has_y_marks_old != has_y_marks)
565 draw_parts |= (PART_FRAME & (~(PART_BORDER_W | PART_BORDER_E)));
567 draw_parts |= border_get_changed_border_parts(
568 fw, &sidebar_g_old, &br->sidebar_g, cs);
569 draw_parts &= (PART_FRAME | PART_HANDLES);
571 return draw_parts;
574 static window_parts border_get_tb_parts_to_draw(
575 FvwmWindow *fw, titlebar_descr *td, rectangle *old_g, rectangle *new_g,
576 window_parts force_draw_parts)
578 window_parts draw_parts;
579 ButtonState old_state;
580 int i;
581 DecorFace *df,*tdf;
583 td->tbstate.draw_bmask = 0;
584 draw_parts = PART_NONE;
585 /* first time? */
586 draw_parts |= (~(fw->decor_state.parts_drawn) & PART_TITLE);
587 td->tbstate.draw_bmask |= (~(fw->decor_state.buttons_drawn));
588 /* forced? */
589 draw_parts |= force_draw_parts;
590 td->tbstate.draw_bmask |= (force_draw_parts & PART_BUTTONS) ? ~0 : 0;
591 /* check if state changed */
592 old_state = border_flags_to_button_state(
593 (fw->decor_state.parts_inverted & PART_TITLE),
594 (fw->decor_state.parts_lit & PART_TITLE), 0);
595 if (old_state != td->tbstate.tstate)
597 draw_parts |= PART_TITLE;
599 /* size changed? */
600 if ((td->old_layout.title_g.width != td->layout.title_g.width ||
601 td->old_layout.title_g.height != td->layout.title_g.height) &&
602 td->layout.title_g.x >= 0 && td->layout.title_g.y >= 0)
604 draw_parts |= PART_TITLE;
606 /* same for buttons */
607 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
609 unsigned int mask = (1 << i);
611 if (FW_W_BUTTON(fw, i) == None)
613 continue;
615 old_state = border_flags_to_button_state(
616 (fw->decor_state.buttons_inverted & mask),
617 (fw->decor_state.buttons_lit & mask),
618 (fw->decor_state.buttons_toggled & mask));
619 if (old_state != td->tbstate.bstate[i])
621 draw_parts |= PART_BUTTONS;
622 td->tbstate.draw_bmask |= mask;
624 if ((td->old_layout.button_g[i].width !=
625 td->layout.button_g[i].width ||
626 td->old_layout.button_g[i].height !=
627 td->layout.button_g[i].height) &&
628 td->layout.button_g[i].x >= 0 &&
629 td->layout.button_g[i].y >= 0)
631 draw_parts |= PART_BUTTONS;
632 td->tbstate.draw_bmask |= mask;
635 /* position changed and background is tiled or a cset? */
636 if ((draw_parts & PART_TITLE) == PART_NONE &&
637 td->layout.title_g.x >= 0 &&
638 td->layout.title_g.y >= 0)
640 df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
641 if (DFS_USE_BORDER_STYLE(df->style) &&
642 (((td->old_layout.title_g.x != td->layout.title_g.x ||
643 td->old_layout.title_g.y != td->layout.title_g.y) &&
644 ((td->cd->valuemask & CWBackPixmap) ||
645 CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
647 (old_g->width != new_g->width &&
648 CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
650 (old_g->height != new_g->height
651 && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
653 ((old_g->x != new_g->x || old_g->y != new_g->y)
654 && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
656 draw_parts |= PART_TITLE;
658 if ((draw_parts & PART_TITLE) == PART_NONE &&
659 (old_g->x != new_g->x || old_g->y != new_g->y))
661 for (tdf = df; tdf != NULL; tdf = tdf->next)
663 if (DFS_FACE_TYPE(tdf->style) ==
664 ColorsetButton &&
665 CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
667 draw_parts |= PART_TITLE;
668 break;
673 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
675 unsigned int mask;
676 DecorFaceStyle *bs;
678 mask = (1 << i);
679 bs = &TB_STATE(
680 GetDecor(fw, buttons[i]))[td->tbstate.bstate[i]].style;
681 if ((td->tbstate.draw_bmask & mask) ||
682 td->layout.button_g[i].x < 0 ||
683 td->layout.button_g[i].y < 0)
685 continue;
687 if (DFS_USE_BORDER_STYLE(*bs) &&
688 (((td->old_layout.button_g[i].x !=
689 td->layout.button_g[i].x||
690 td->old_layout.button_g[i].y !=
691 td->layout.button_g[i].y)
692 && ((td->cd->valuemask & CWBackPixmap) ||
693 CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs)))
695 (old_g->width != new_g->width &&
696 CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs))
698 (old_g->height != new_g->height
699 && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs))
701 ((old_g->x != new_g->x || old_g->y != new_g->y)
702 && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs))))
704 td->tbstate.draw_bmask |= mask;
706 else if (DFS_USE_TITLE_STYLE(*bs))
708 df = &TB_STATE(GetDecor(
709 fw, titlebar))[td->tbstate.bstate[i]];
710 for(tdf = df; tdf != NULL; tdf = tdf->next)
712 int cs;
713 if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
715 /* can be improved */
716 td->tbstate.draw_bmask |= mask;
717 break;
719 if (DFS_FACE_TYPE(tdf->style) != ColorsetButton
720 || !CSET_HAS_PIXMAP(tdf->u.acs.cs))
722 continue;
724 cs = tdf->u.acs.cs;
725 if(((td->old_layout.button_g[i].x !=
726 td->layout.button_g[i].x ||
727 td->old_layout.button_g[i].y !=
728 td->layout.button_g[i].y) ||
729 CSET_PIXMAP_IS_TILED(cs))
731 (old_g->width != new_g->width &&
732 CSET_PIXMAP_IS_X_STRETCHED(cs))
734 (old_g->height != new_g->height &&
735 CSET_PIXMAP_IS_Y_STRETCHED(cs))
737 ((old_g->x != new_g->x ||
738 old_g->y != new_g->y)
739 && CSET_IS_TRANSPARENT_ROOT(cs)))
741 td->tbstate.draw_bmask |= mask;
742 break;
746 if (td->tbstate.draw_bmask & mask)
748 continue;
750 if (old_g->x != new_g->x || old_g->y != new_g->y)
752 df = &TB_STATE(GetDecor(
753 fw, buttons[i]))[td->tbstate.bstate[i]];
754 for(tdf = df; tdf != NULL; tdf = tdf->next)
756 if (DFS_FACE_TYPE(tdf->style) ==
757 ColorsetButton &&
758 CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
760 td->tbstate.draw_bmask |= mask;
761 break;
766 td->tbstate.max_bmask = 0;
767 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
769 if (FW_W_BUTTON(fw, i) == None)
771 continue;
773 if ((i & 1) == 1 && i / 2 < Scr.nr_right_buttons)
775 td->tbstate.max_bmask |= (1 << i);
777 else if ((i & 1) == 0 && i / 2 < Scr.nr_left_buttons)
779 td->tbstate.max_bmask |= (1 << i);
782 td->tbstate.draw_bmask &= td->tbstate.max_bmask;
783 td->tbstate.pressed_bmask &= td->tbstate.max_bmask;
784 td->tbstate.lit_bmask &= td->tbstate.max_bmask;
785 td->tbstate.toggled_bmask &= td->tbstate.max_bmask;
786 td->tbstate.clear_bmask &= td->tbstate.max_bmask;
787 if (td->tbstate.draw_bmask == 0)
789 draw_parts &= ~PART_BUTTONS;
791 else
793 draw_parts |= PART_BUTTONS;
795 draw_parts &= PART_TITLEBAR;
797 return draw_parts;
800 static void border_get_border_gcs(
801 draw_border_gcs *ret_gcs, common_decorations_type *cd, FvwmWindow *fw,
802 Bool do_hilight)
804 static GC transparent_gc = None;
805 DecorFaceStyle *borderstyle;
806 Bool is_reversed = False;
808 if (transparent_gc == None && !HAS_NO_BORDER(fw) && !HAS_MWM_BORDER(fw))
810 XGCValues xgcv;
812 xgcv.function = GXnoop;
813 xgcv.plane_mask = 0;
814 transparent_gc = fvwmlib_XCreateGC(
815 dpy, Scr.NoFocusWin, GCFunction | GCPlaneMask, &xgcv);
817 ret_gcs->transparent = transparent_gc;
818 /* get the border style bits */
819 borderstyle = (do_hilight) ?
820 &GetDecor(fw, BorderStyle.active.style) :
821 &GetDecor(fw, BorderStyle.inactive.style);
822 if (borderstyle->flags.button_relief == DFS_BUTTON_IS_SUNK)
824 is_reversed = True;
826 if (is_reversed)
828 ret_gcs->shadow = cd->relief_gc;
829 ret_gcs->relief = cd->shadow_gc;
831 else
833 ret_gcs->relief = cd->relief_gc;
834 ret_gcs->shadow = cd->shadow_gc;
837 return;
840 static void trim_border_layout(
841 FvwmWindow *fw, DecorFaceStyle *borderstyle,
842 border_relief_size_descr *ret_size_descr)
844 /* If the border is too thin to accomodate the standard look, we remove
845 * parts of the border so that at least one pixel of the original
846 * colour is visible. We make an exception for windows with a border
847 * width of 2, though. */
848 if ((!IS_SHADED(fw) || HAS_TITLE(fw)) && fw->boundary_width == 2)
850 ret_size_descr->trim--;
852 if (ret_size_descr->trim < 0)
854 ret_size_descr->trim = 0;
856 for ( ; ret_size_descr->trim > 0; ret_size_descr->trim--)
858 if (ret_size_descr->w_hiout > 1)
860 ret_size_descr->w_hiout--;
862 else if (ret_size_descr->w_shin > 0)
864 ret_size_descr->w_shin--;
866 else if (ret_size_descr->w_hiout > 0)
868 ret_size_descr->w_hiout--;
870 else if (ret_size_descr->w_trout > 0)
872 ret_size_descr->w_trout = 0;
873 ret_size_descr->w_trin = 0;
874 ret_size_descr->w_din = 0;
875 ret_size_descr->w_hiout = 1;
877 ret_size_descr->sum--;
879 ret_size_descr->w_c = fw->boundary_width - ret_size_descr->sum;
881 return;
884 static void check_remove_inset(
885 DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr)
887 if (!DFS_HAS_NO_INSET(*borderstyle))
889 return;
891 ret_size_descr->w_shin = 0;
892 ret_size_descr->sum--;
893 ret_size_descr->trim--;
894 if (ret_size_descr->w_trin)
896 ret_size_descr->w_trout = 0;
897 ret_size_descr->w_trin = 0;
898 ret_size_descr->w_din = 0;
899 ret_size_descr->w_hiout = 1;
900 ret_size_descr->sum -= 2;
901 ret_size_descr->trim -= 2;
904 return;
907 static void border_fetch_mwm_layout(
908 FvwmWindow *fw, DecorFaceStyle *borderstyle,
909 border_relief_size_descr *ret_size_descr)
911 /* MWM borders look like this:
913 * HHCCCCS from outside to inside on the left and top border
914 * SSCCCCH from outside to inside on the bottom and right border
915 * |||||||
916 * |||||||__ w_shin (inner shadow area)
917 * ||||||___ w_c (transparent area)
918 * |||||____ w_c (transparent area)
919 * ||||_____ w_c (transparent area)
920 * |||______ w_c (transparent area)
921 * ||_______ w_hiout (outer hilight area)
922 * |________ w_hiout (outer hilight area)
925 * C = original colour
926 * H = hilight
927 * S = shadow
929 ret_size_descr->w_dout = 0;
930 ret_size_descr->w_hiout = 2;
931 ret_size_descr->w_trout = 0;
932 ret_size_descr->w_trin = 0;
933 ret_size_descr->w_shin = 1;
934 ret_size_descr->w_din = 0;
935 ret_size_descr->sum = 3;
936 ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width + 1;
937 check_remove_inset(borderstyle, ret_size_descr);
938 trim_border_layout(fw, borderstyle, ret_size_descr);
940 return;
943 static void border_fetch_fvwm_layout(
944 FvwmWindow *fw, DecorFaceStyle *borderstyle,
945 border_relief_size_descr *ret_size_descr)
947 /* Fvwm borders look like this:
949 * SHHCCSS from outside to inside on the left and top border
950 * SSCCHHS from outside to inside on the bottom and right border
951 * |||||||
952 * |||||||__ w_din (inner dark area)
953 * ||||||___ w_shin (inner shadow area)
954 * |||||____ w_trin (inner transparent/shadow area)
955 * ||||_____ w_c (transparent area)
956 * |||______ w_trout (outer transparent/hilight area)
957 * ||_______ w_hiout (outer hilight area)
958 * |________ w_dout (outer dark area)
960 * C = original colour
961 * H = hilight
962 * S = shadow
964 * reduced to 5 pixels it looks like this:
966 * SHHCS
967 * SSCHS
968 * |||||
969 * |||||__ w_din (inner dark area)
970 * ||||___ w_trin (inner transparent/shadow area)
971 * |||____ w_trout (outer transparent/hilight area)
972 * ||_____ w_hiout (outer hilight area)
973 * |______ w_dout (outer dark area)
975 ret_size_descr->w_dout = 1;
976 ret_size_descr->w_hiout = 1;
977 ret_size_descr->w_trout = 1;
978 ret_size_descr->w_trin = 1;
979 ret_size_descr->w_shin = 1;
980 ret_size_descr->w_din = 1;
981 /* w_trout + w_trin counts only as one pixel of border because
982 * they let one pixel of the original colour shine through. */
983 ret_size_descr->sum = 6;
984 ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width;
985 check_remove_inset(borderstyle, ret_size_descr);
986 trim_border_layout(fw, borderstyle, ret_size_descr);
988 return;
991 static void border_get_border_relief_size_descr(
992 border_relief_size_descr *ret_size_descr, FvwmWindow *fw,
993 Bool do_hilight)
995 DecorFaceStyle *borderstyle;
997 if (is_window_border_minimal(fw))
999 /* the border is too small, only a background but no relief */
1000 ret_size_descr->is_flat = 1;
1001 return;
1003 borderstyle = (do_hilight) ?
1004 &GetDecor(fw, BorderStyle.active.style) :
1005 &GetDecor(fw, BorderStyle.inactive.style);
1006 if (borderstyle->flags.button_relief == DFS_BUTTON_IS_FLAT)
1008 ret_size_descr->is_flat = 1;
1009 return;
1011 ret_size_descr->is_flat = 0;
1012 /* get the relief layout */
1013 if (HAS_MWM_BORDER(fw))
1015 border_fetch_mwm_layout(fw, borderstyle, ret_size_descr);
1017 else
1019 border_fetch_fvwm_layout(fw, borderstyle, ret_size_descr);
1022 return;
1025 static void border_get_border_marks_descr(
1026 common_decorations_type *cd, border_relief_descr *br, FvwmWindow *fw)
1028 int inset;
1030 /* get mark's length and thickness */
1031 inset = (br->relief.w_shin != 0 || br->relief.w_din != 0);
1032 br->marks.length = fw->boundary_width - br->relief.w_dout - inset;
1033 if (br->marks.length <= 0)
1035 br->marks.has_x_marks = 0;
1036 br->marks.has_y_marks = 0;
1037 return;
1039 br->marks.thickness = cd->relief_width;
1040 if (br->marks.thickness > br->marks.length)
1042 br->marks.thickness = br->marks.length;
1044 /* get offsets from outer side of window */
1045 br->marks.offset_tl = br->relief.w_dout;
1046 br->marks.offset_br =
1047 -br->relief.w_dout - br->marks.length - br->marks.offset_tl;
1049 return;
1052 static Pixmap border_create_decor_pixmap(
1053 common_decorations_type *cd, rectangle *decor_g)
1055 Pixmap p;
1057 p = XCreatePixmap(
1058 dpy, Scr.Root, decor_g->width, decor_g->height, Pdepth);
1060 return p;
1063 static void border_draw_part_relief(
1064 border_relief_descr *br, rectangle *frame_g, rectangle *part_g,
1065 Pixmap dest_pix, Bool is_inverted)
1067 int i;
1068 int off_x = 0;
1069 int off_y = 0;
1070 int width = frame_g->width - 1;
1071 int height = frame_g->height - 1;
1072 int w[7];
1073 GC gc[4];
1075 w[0] = br->relief.w_dout;
1076 w[1] = br->relief.w_hiout;
1077 w[2] = br->relief.w_trout;
1078 w[3] = br->relief.w_c;
1079 w[4] = br->relief.w_trin;
1080 w[5] = br->relief.w_shin;
1081 w[6] = br->relief.w_din;
1082 gc[(is_inverted == True)] = br->gcs.relief;
1083 gc[!(is_inverted == True)] = br->gcs.shadow;
1084 gc[2] = br->gcs.transparent;
1085 gc[3] = br->gcs.shadow;
1087 off_x = -part_g->x;
1088 off_y = -part_g->y;
1089 width = frame_g->width - 1;
1090 height = frame_g->height - 1;
1091 for (i = 0; i < 7; i++)
1093 if (ulgc[i] != 0x7f && w[i] > 0)
1095 do_relieve_rectangle(
1096 dpy, dest_pix, off_x, off_y,
1097 width, height, gc[(int)ulgc[i]],
1098 gc[(int)brgc[i]], w[i], False);
1100 off_x += w[i];
1101 off_y += w[i];
1102 width -= 2 * w[i];
1103 height -= 2 * w[i];
1106 return;
1109 static void border_draw_x_mark(
1110 border_relief_descr *br, int x, int y, Pixmap dest_pix,
1111 Bool do_draw_shadow)
1113 int k;
1114 int length;
1115 GC gc;
1117 if (br->marks.has_x_marks == 0)
1119 return;
1121 x += br->marks.offset_tl;
1122 gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
1123 /* draw it */
1124 for (k = 0, length = br->marks.length - 1; k < br->marks.thickness;
1125 k++, length--)
1127 int x1;
1128 int x2;
1129 int y1;
1130 int y2;
1132 if (length < 0)
1134 break;
1136 if (do_draw_shadow)
1138 x1 = x + k;
1139 y1 = y - 1 - k;
1141 else
1143 x1 = x;
1144 y1 = y + k;
1146 x2 = x1 + length;
1147 y2 = y1;
1148 XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
1151 return;
1154 static void border_draw_y_mark(
1155 border_relief_descr *br, int x, int y, Pixmap dest_pix,
1156 Bool do_draw_shadow)
1158 int k;
1159 int length;
1160 GC gc;
1162 if (br->marks.has_y_marks == 0)
1164 return;
1166 y += br->marks.offset_tl;
1167 gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief;
1168 /* draw it */
1169 for (k = 0, length = br->marks.length; k < br->marks.thickness;
1170 k++, length--)
1172 int x1;
1173 int x2;
1174 int y1;
1175 int y2;
1177 if (length <= 0)
1179 break;
1181 if (do_draw_shadow)
1183 x1 = x - 1 - k;
1184 y1 = y + k;
1186 else
1188 x1 = x + k;
1189 y1 = y;
1191 x2 = x1;
1192 y2 = y1 + length - 1;
1193 XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2);
1196 return;
1199 static void border_draw_part_marks(
1200 border_relief_descr *br, rectangle *part_g, window_parts part,
1201 Pixmap dest_pix)
1203 int l;
1204 int t;
1205 int w;
1206 int h;
1207 int o;
1209 l = br->sidebar_g.x;
1210 t = br->sidebar_g.y;
1211 w = part_g->width;
1212 h = part_g->height;
1213 o = br->marks.offset_br;
1214 switch (part)
1216 case PART_BORDER_N:
1217 border_draw_y_mark(br, 0, 0, dest_pix, False);
1218 border_draw_y_mark(br, w, 0, dest_pix, True);
1219 break;
1220 case PART_BORDER_S:
1221 border_draw_y_mark(br, 0, h + o, dest_pix, False);
1222 border_draw_y_mark(br, w, h + o, dest_pix, True);
1223 break;
1224 case PART_BORDER_E:
1225 border_draw_x_mark(br, w + o, 0, dest_pix, False);
1226 border_draw_x_mark(br, w + o, h, dest_pix, True);
1227 break;
1228 case PART_BORDER_W:
1229 border_draw_x_mark(br, 0, 0, dest_pix, False);
1230 border_draw_x_mark(br, 0, h, dest_pix, True);
1231 break;
1232 case PART_BORDER_NW:
1233 border_draw_x_mark(br, 0, t, dest_pix, True);
1234 border_draw_y_mark(br, l, 0, dest_pix, True);
1235 break;
1236 case PART_BORDER_NE:
1237 border_draw_x_mark(br, l + o, t, dest_pix, True);
1238 border_draw_y_mark(br, 0, 0, dest_pix, False);
1239 break;
1240 case PART_BORDER_SW:
1241 border_draw_x_mark(br, 0, 0, dest_pix, False);
1242 border_draw_y_mark(br, l, t + o, dest_pix, True);
1243 break;
1244 case PART_BORDER_SE:
1245 border_draw_x_mark(br, l + o, 0, dest_pix, False);
1246 border_draw_y_mark(br, 0, t + o, dest_pix, False);
1247 break;
1248 default:
1249 return;
1252 return;
1255 inline static void border_set_part_background(
1256 Window w, Pixmap pix)
1258 XSetWindowAttributes xswa;
1260 xswa.background_pixmap = pix;
1261 XChangeWindowAttributes(dpy, w, CWBackPixmap, &xswa);
1263 return;
1266 /* render the an image into the pixmap */
1267 static void border_fill_pixmap_background(
1268 Pixmap dest_pix, rectangle *dest_g, pixmap_background_type *bg,
1269 common_decorations_type *cd)
1271 Bool do_tile;
1272 Bool do_stretch;
1273 XGCValues xgcv;
1274 unsigned long valuemask;
1275 Pixmap p = None, shape = None, alpha = None;
1276 int src_width, src_height;
1278 do_tile = (bg->flags.use_pixmap && bg->pixmap.flags.is_tiled) ?
1279 True : False;
1280 do_stretch = (bg->flags.use_pixmap && bg->pixmap.flags.is_stretched) ?
1281 True : False;
1282 xgcv.fill_style = FillSolid;
1283 valuemask = GCFillStyle;
1284 if (!bg->flags.use_pixmap)
1286 /* solid pixel */
1287 xgcv.foreground = bg->pixel;
1288 xgcv.clip_x_origin = 0;
1289 xgcv.clip_y_origin = 0;
1290 xgcv.clip_mask = None;
1291 valuemask |= GCForeground | GCClipMask | GCClipXOrigin |
1292 GCClipYOrigin;
1293 XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1294 XFillRectangle(
1295 dpy, dest_pix, Scr.BordersGC, dest_g->x, dest_g->y,
1296 dest_g->width - dest_g->x, dest_g->height - dest_g->y);
1297 return;
1300 if (do_stretch)
1302 if (bg->pixmap.p)
1304 p = CreateStretchPixmap(
1305 dpy, bg->pixmap.p,
1306 bg->pixmap.g.width, bg->pixmap.g.height,
1307 bg->pixmap.depth,
1308 bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1309 (bg->pixmap.depth == 1)?
1310 Scr.MonoGC:Scr.BordersGC);
1312 if (bg->pixmap.shape)
1314 shape = CreateStretchPixmap(
1315 dpy, bg->pixmap.shape,
1316 bg->pixmap.g.width, bg->pixmap.g.height, 1,
1317 bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1318 Scr.MonoGC);
1320 if (bg->pixmap.alpha)
1322 alpha = CreateStretchPixmap(
1323 dpy, bg->pixmap.alpha,
1324 bg->pixmap.g.width, bg->pixmap.g.height,
1325 FRenderGetAlphaDepth(),
1326 bg->pixmap.stretch_w, bg->pixmap.stretch_h,
1327 Scr.AlphaGC);
1329 src_width = bg->pixmap.stretch_w;
1330 src_height = bg->pixmap.stretch_h;
1332 else
1334 p = bg->pixmap.p;
1335 shape = bg->pixmap.shape;
1336 alpha = bg->pixmap.alpha;
1337 src_width = bg->pixmap.g.width;
1338 src_height = bg->pixmap.g.height;
1341 if (do_tile == False)
1343 /* pixmap, offset stored in dest_g->x/y */
1344 xgcv.foreground = cd->fore_color;
1345 xgcv.background = cd->back_color;
1346 valuemask |= GCForeground|GCBackground;
1347 XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1348 PGraphicsRenderPixmaps(
1349 dpy, Scr.NoFocusWin, p, shape, alpha,
1350 bg->pixmap.depth, &(bg->pixmap.fra),
1351 dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
1352 bg->pixmap.g.x, bg->pixmap.g.y,
1353 src_width, src_height,
1354 dest_g->x, dest_g->y, dest_g->width - dest_g->x,
1355 dest_g->height - dest_g->y, False);
1357 else
1359 /* tiled pixmap */
1360 xgcv.foreground = cd->fore_color;
1361 xgcv.background = cd->back_color;
1362 valuemask |= GCForeground|GCBackground;
1363 XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv);
1364 PGraphicsRenderPixmaps(
1365 dpy, Scr.NoFocusWin, p, shape, alpha,
1366 bg->pixmap.depth, &(bg->pixmap.fra),
1367 dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC,
1368 bg->pixmap.g.x, bg->pixmap.g.y,
1369 src_width, src_height,
1370 dest_g->x, dest_g->y,
1371 dest_g->width - dest_g->x,
1372 dest_g->height - dest_g->y, True);
1374 if (p && p != bg->pixmap.p)
1376 XFreePixmap(dpy, p);
1378 if (shape && shape != bg->pixmap.shape)
1380 XFreePixmap(dpy, shape);
1382 if (alpha && alpha != bg->pixmap.alpha)
1384 XFreePixmap(dpy, alpha);
1386 return;
1389 /* create a root transparent colorset bg, we take in account a possible
1390 * drawing rotation */
1391 static Pixmap border_create_root_transparent_pixmap(
1392 titlebar_descr *td, Window w, int width, int height, int cs)
1394 int my_w, my_h;
1395 Pixmap p;
1397 if (!CSET_IS_TRANSPARENT_ROOT(cs))
1399 return None;
1401 if (td->td_is_rotated &&
1402 (td->draw_rotation == ROTATION_90 ||
1403 td->draw_rotation == ROTATION_270))
1405 my_h = width;
1406 my_w = height;
1408 else
1410 my_w = width;
1411 my_h = height;
1413 p = CreateBackgroundPixmap(
1414 dpy, w, my_w, my_h, &Colorset[cs],
1415 Pdepth, Scr.BordersGC, False);
1416 if (p && td->td_is_rotated)
1418 Pixmap tmp;
1419 tmp = CreateRotatedPixmap(
1420 dpy, p, my_w, my_h, Pdepth, Scr.BordersGC,
1421 td->restore_rotation);
1422 XFreePixmap(dpy, p);
1423 p = tmp;
1425 return p;
1428 static void border_get_frame_pixmap(
1429 common_decorations_type *cd, rectangle *frame_g)
1431 dynamic_common_decorations *dcd = &(cd->dynamic_cd);
1433 if (dcd->frame_pixmap != None)
1435 /* should not happen */
1436 fprintf(stderr, "Bad use of border_get_frame_pixmap!!\n");
1437 dcd->frame_pixmap = None;
1440 if (cd->bg_border_cs < 0 || CSET_IS_TRANSPARENT(cd->bg_border_cs))
1442 /* should not happen */
1444 else
1446 dcd->frame_pixmap = CreateBackgroundPixmap(
1447 dpy, Scr.NoFocusWin, frame_g->width, frame_g->height,
1448 &Colorset[cd->bg_border_cs], Pdepth, Scr.BordersGC,
1449 False);
1451 return;
1454 static void border_get_border_background(
1455 pixmap_background_type *bg, common_decorations_type *cd,
1456 rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window w)
1458 *free_bg_pixmap = False;
1460 if (cd->texture_pixmap)
1462 bg->flags.use_pixmap = 1;
1463 bg->pixmap.p = cd->texture_pixmap;
1464 bg->pixmap.g.width = cd->texture_pixmap_width;
1465 bg->pixmap.g.height = cd->texture_pixmap_height;
1466 bg->pixmap.shape = None;
1467 bg->pixmap.alpha = None;
1468 bg->pixmap.depth = Pdepth;
1469 bg->pixmap.flags.is_tiled = 1;
1470 bg->pixmap.flags.is_stretched = 0;
1471 bg->pixmap.fra.mask = 0;
1473 else if (cd->bg_border_cs >= 0 &&
1474 !CSET_IS_TRANSPARENT_PR(cd->bg_border_cs))
1476 colorset_t *cs_t = &Colorset[cd->bg_border_cs];
1477 XGCValues xgcv;
1479 if (CSET_IS_TRANSPARENT_ROOT(cd->bg_border_cs))
1481 bg->pixmap.p = CreateBackgroundPixmap(
1482 dpy, w, part_g->width, part_g->height, cs_t,
1483 Pdepth, Scr.BordersGC, False);
1485 else
1487 /* FIXME */
1488 if (cd->dynamic_cd.frame_pixmap == None)
1490 border_get_frame_pixmap(cd, relative_g);
1492 bg->pixmap.p = XCreatePixmap(
1493 dpy, cd->dynamic_cd.frame_pixmap, part_g->width,
1494 part_g->height, Pdepth);
1495 xgcv.fill_style = FillTiled;
1496 xgcv.tile = cd->dynamic_cd.frame_pixmap;
1497 xgcv.ts_x_origin = - relative_g->x;
1498 xgcv.ts_y_origin = - relative_g->y;
1499 XChangeGC(
1500 dpy, Scr.BordersGC, GCTile | GCTileStipXOrigin |
1501 GCTileStipYOrigin | GCFillStyle, &xgcv);
1502 XFillRectangle(
1503 dpy, bg->pixmap.p, Scr.BordersGC, 0, 0,
1504 part_g->width, part_g->height);
1505 xgcv.fill_style = FillSolid;
1506 XChangeGC(dpy, Scr.BordersGC, GCFillStyle, &xgcv);
1508 bg->pixmap.g.width = part_g->width;
1509 bg->pixmap.g.height = part_g->height;
1510 bg->flags.use_pixmap = 1;
1511 bg->pixmap.shape = None;
1512 bg->pixmap.alpha = None;
1513 bg->pixmap.depth = Pdepth;
1514 bg->pixmap.flags.is_tiled = 1;
1515 bg->pixmap.flags.is_stretched = 0;
1516 bg->pixmap.fra.mask = 0;
1517 *free_bg_pixmap = True;
1519 else
1521 bg->flags.use_pixmap = 0;
1522 bg->pixel = cd->attributes.background_pixel;
1525 return;
1528 static void border_draw_one_border_part(
1529 common_decorations_type *cd, FvwmWindow *fw, rectangle *sidebar_g,
1530 rectangle *frame_g, border_relief_descr *br, window_parts part,
1531 window_parts draw_handles, Bool is_inverted, Bool do_clear)
1533 pixmap_background_type bg;
1534 rectangle part_g;
1535 rectangle pix_g;
1536 rectangle relative_g;
1537 Pixmap p;
1538 Window w;
1539 Bool free_bg_pixmap = False;
1541 /* make a pixmap */
1542 border_get_part_geometry(fw, part, sidebar_g, &part_g, &w);
1543 if (part_g.width <= 0 || part_g.height <= 0)
1545 return;
1547 p = border_create_decor_pixmap(cd, &part_g);
1548 /* set the background tile */
1549 relative_g.width = fw->g.frame.width;
1550 relative_g.height = fw->g.frame.height;
1551 relative_g.x = part_g.x;
1552 relative_g.y = part_g.y;
1553 border_get_border_background(
1554 &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w);
1555 if (cd->texture_pixmap)
1557 switch (part)
1559 case PART_BORDER_E:
1560 bg.pixmap.g.x = frame_g->width - fw->boundary_width;
1561 break;
1562 case PART_BORDER_NE:
1563 case PART_BORDER_SE:
1564 bg.pixmap.g.x = frame_g->width - fw->corner_width;
1565 break;
1566 case PART_BORDER_N:
1567 case PART_BORDER_S:
1568 bg.pixmap.g.x = fw->corner_width;
1569 break;
1570 default:
1571 bg.pixmap.g.x = 0;
1572 break;
1574 switch (part)
1576 case PART_BORDER_S:
1577 bg.pixmap.g.y = frame_g->height - fw->boundary_width;
1578 break;
1579 case PART_BORDER_SW:
1580 case PART_BORDER_SE:
1581 bg.pixmap.g.y = frame_g->height - fw->corner_width;
1582 break;
1583 case PART_BORDER_W:
1584 case PART_BORDER_E:
1585 bg.pixmap.g.y = fw->corner_width;
1586 break;
1587 default:
1588 bg.pixmap.g.y = 0;
1589 break;
1592 else
1594 bg.pixmap.g.x = 0;
1595 bg.pixmap.g.y = 0;
1597 /* set the geometry for drawing the Tiled pixmap; maybe add the relief
1598 * as offset? */
1599 pix_g.x = 0;
1600 pix_g.y = 0;
1601 pix_g.width = part_g.width;
1602 pix_g.height = part_g.height;
1603 border_fill_pixmap_background(p, &pix_g, &bg, cd);
1604 if (free_bg_pixmap && bg.pixmap.p)
1606 XFreePixmap(dpy, bg.pixmap.p);
1608 /* draw the relief over the background */
1609 if (!br->relief.is_flat)
1611 border_draw_part_relief(br, frame_g, &part_g, p, is_inverted);
1612 /* draw the handle marks */
1613 if (br->marks.has_x_marks || br->marks.has_y_marks)
1615 border_draw_part_marks(br, &part_g, part, p);
1618 /* apply the pixmap and destroy it */
1619 border_set_part_background(w, p);
1620 if (do_clear == True)
1622 XClearWindow(dpy,w);
1624 XFreePixmap(dpy, p);
1626 return;
1629 static void border_draw_all_border_parts(
1630 common_decorations_type *cd, FvwmWindow *fw, border_relief_descr *br,
1631 rectangle *frame_g, window_parts draw_parts,
1632 window_parts pressed_parts, Bool do_hilight, Bool do_clear)
1634 window_parts part;
1635 window_parts draw_handles;
1637 /* get the description of the drawing directives */
1638 border_get_border_relief_size_descr(&br->relief, fw, do_hilight);
1639 border_get_border_marks_descr(cd, br, fw);
1640 /* fetch the gcs used to draw the border */
1641 border_get_border_gcs(&br->gcs, cd, fw, do_hilight);
1642 /* draw everything in a big loop */
1643 draw_parts &= (PART_FRAME | PART_HANDLES);
1644 draw_handles = (draw_parts & PART_HANDLES);
1646 for (part = PART_BORDER_N; (part & PART_FRAME); part <<= 1)
1648 if (part & draw_parts)
1650 border_draw_one_border_part(
1651 cd, fw, &br->sidebar_g, frame_g, br, part,
1652 draw_handles,
1653 (pressed_parts & part) ? True : False,
1654 do_clear);
1658 return;
1663 * Draws a little pattern within a window (more complex)
1666 static void border_draw_vector_to_pixmap(
1667 Pixmap dest_pix, common_decorations_type *cd, int is_toggled,
1668 struct vector_coords *coords, rectangle *pixmap_g)
1670 GC gcs[4];
1671 int i;
1673 if (coords->use_fgbg == 1)
1675 Globalgcv.foreground = cd->fore_color;
1676 Globalgcm = GCForeground;
1677 XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv);
1678 Globalgcv.foreground = cd->back_color;
1679 XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv);
1680 gcs[3] = Scr.ScratchGC3; /* @3 is fg */
1681 gcs[2] = Scr.ScratchGC4; /* @2 is bg */
1683 if (is_toggled)
1685 gcs[0] = cd->relief_gc;
1686 gcs[1] = cd->shadow_gc;
1688 else
1690 gcs[0] = cd->shadow_gc;
1691 gcs[1] = cd->relief_gc;
1693 for (i = 1; i < coords->num; i++)
1695 if (coords->c[i] < 0 || coords->c[i] >= 4)
1697 /* don't draw a line */
1698 continue;
1700 XDrawLine(
1701 dpy, dest_pix, gcs[coords->c[i]],
1702 pixmap_g->width * coords->x[i-1] / 100 +
1703 coords->xoff[i-1],
1704 pixmap_g->height * coords->y[i-1] / 100 +
1705 coords->yoff[i-1],
1706 pixmap_g->width * coords->x[i] / 100 +
1707 coords->xoff[i],
1708 pixmap_g->height * coords->y[i] / 100 +
1709 coords->yoff[i]);
1712 return;
1717 * Handle Title pixmaps used for UseTitleStyle
1720 static void border_setup_bar_pixmaps(
1721 titlebar_descr *td, dynamic_common_decorations *dcd, DecorFace *df,
1722 ButtonState bs)
1724 int count = dcd->bar_pixmaps[bs].count;
1725 DecorFace *tsdf;
1726 int i, j, mp_part_left, mp_part_right;
1728 if (count != 0)
1730 /* ok */
1731 return;
1734 for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
1736 if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
1738 count++;
1740 else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
1742 border_mp_get_use_title_style_parts_and_geometry(
1743 td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1744 tsdf->u.mp.solid_flags, True, NULL,
1745 &mp_part_left);
1746 border_mp_get_use_title_style_parts_and_geometry(
1747 td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1748 tsdf->u.mp.solid_flags, False, NULL,
1749 &mp_part_right);
1750 for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
1752 if (j != mp_part_left && j != mp_part_right)
1754 continue;
1756 if (tsdf->u.mp.acs[j].cs >= 0 ||
1757 tsdf->u.mp.pixmaps[j])
1759 count++;
1764 if (count == 0)
1766 dcd->bar_pixmaps[bs].count = -1;
1767 return;
1769 else
1771 dcd->bar_pixmaps[bs].bps =
1772 (bar_pixmap *)safemalloc(count*sizeof(bar_pixmap));
1774 dcd->bar_pixmaps[bs].count = count;
1775 i = 0;
1776 for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
1778 if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton)
1780 dcd->bar_pixmaps[bs].bps[i].p = None;
1781 dcd->bar_pixmaps[bs].bps[i].mp_created_pic = NULL;
1782 dcd->bar_pixmaps[bs].bps[i].cs = tsdf->u.acs.cs;
1783 dcd->bar_pixmaps[bs].bps[i].mp_pic = NULL;
1784 dcd->bar_pixmaps[bs].bps[i].created = 0;
1785 dcd->bar_pixmaps[bs].bps[i].mp_part = TBMP_NONE;
1786 i++;
1788 else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap)
1790 border_mp_get_use_title_style_parts_and_geometry(
1791 td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1792 tsdf->u.mp.solid_flags, True, NULL,
1793 &mp_part_left);
1794 border_mp_get_use_title_style_parts_and_geometry(
1795 td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs,
1796 tsdf->u.mp.solid_flags, False, NULL,
1797 &mp_part_right);
1798 for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++)
1800 if (j != mp_part_left && j != mp_part_right)
1802 continue;
1804 if (tsdf->u.mp.acs[j].cs >= 0 ||
1805 tsdf->u.mp.pixmaps[j])
1807 dcd->bar_pixmaps[bs].bps[i].p = None;
1808 dcd->bar_pixmaps[bs].bps[i].
1809 mp_created_pic = NULL;
1810 dcd->bar_pixmaps[bs].bps[i].cs =
1811 tsdf->u.mp.acs[j].cs;
1812 dcd->bar_pixmaps[bs].bps[i].mp_pic =
1813 tsdf->u.mp.pixmaps[j];
1814 dcd->bar_pixmaps[bs].bps[i].created = 0;
1815 dcd->bar_pixmaps[bs].bps[i].mp_part = j;
1816 i++;
1823 static Pixmap border_get_bar_pixmaps(
1824 dynamic_common_decorations *dcd, rectangle *bar_g, ButtonState bs,
1825 int cset, FvwmPicture *mp_pic, int mp_part, int stretch,
1826 FvwmPicture **mp_ret_pic)
1828 ButtonState b;
1829 int i,j;
1830 int count = dcd->bar_pixmaps[bs].count;
1832 if (count <= 0)
1834 return None;
1837 i = 0;
1838 while(i < count &&
1839 (dcd->bar_pixmaps[bs].bps[i].cs != cset ||
1840 dcd->bar_pixmaps[bs].bps[i].mp_part != mp_part ||
1841 dcd->bar_pixmaps[bs].bps[i].mp_pic != mp_pic))
1843 i++;
1845 if (i == count)
1847 return None;
1849 if (mp_ret_pic)
1851 *mp_ret_pic = dcd->bar_pixmaps[bs].bps[i].mp_created_pic;
1853 if (dcd->bar_pixmaps[bs].bps[i].p == None)
1855 /* see if we have it */
1856 b = 0;
1857 while (b < BS_MaxButtonState)
1859 int c = dcd->bar_pixmaps[b].count;
1860 j = 0;
1861 while(j < c &&
1862 (dcd->bar_pixmaps[b].bps[j].cs != cset ||
1863 dcd->bar_pixmaps[b].bps[j].mp_part != mp_part ||
1864 dcd->bar_pixmaps[b].bps[j].mp_pic != mp_pic))
1866 j++;
1868 if (j < c && dcd->bar_pixmaps[b].bps[j].p)
1870 dcd->bar_pixmaps[bs].bps[i].p =
1871 dcd->bar_pixmaps[b].bps[j].p;
1872 if (mp_pic && mp_ret_pic)
1874 *mp_ret_pic =
1875 dcd->bar_pixmaps[bs].bps[i].
1876 mp_created_pic =
1877 dcd->bar_pixmaps[b].bps[j].
1878 mp_created_pic;
1880 break;
1882 b++;
1885 if (dcd->bar_pixmaps[bs].bps[i].p == None)
1887 if (cset >= 0)
1889 dcd->bar_pixmaps[bs].bps[i].p = CreateBackgroundPixmap(
1890 dpy, Scr.NoFocusWin, bar_g->width, bar_g->height,
1891 &Colorset[cset], Pdepth, Scr.BordersGC, False);
1892 dcd->bar_pixmaps[bs].bps[i].created = True;
1894 else if (mp_pic && mp_ret_pic)
1896 if (stretch)
1898 dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
1899 PGraphicsCreateStretchPicture(
1900 dpy, Scr.NoFocusWin, mp_pic,
1901 bar_g->width, bar_g->height,
1902 Scr.BordersGC, Scr.MonoGC,
1903 Scr.AlphaGC);
1905 else
1907 dcd->bar_pixmaps[bs].bps[i].mp_created_pic =
1908 PGraphicsCreateTiledPicture(
1909 dpy, Scr.NoFocusWin, mp_pic,
1910 bar_g->width, bar_g->height,
1911 Scr.BordersGC, Scr.MonoGC,
1912 Scr.AlphaGC);
1914 if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic)
1916 dcd->bar_pixmaps[bs].bps[i].created = True;
1917 *mp_ret_pic =
1918 dcd->bar_pixmaps[bs].bps[i].
1919 mp_created_pic;
1920 dcd->bar_pixmaps[bs].bps[i].p =
1921 dcd->bar_pixmaps[bs].bps[i].
1922 mp_created_pic->picture;
1926 return dcd->bar_pixmaps[bs].bps[i].p;
1929 static void border_free_bar_pixmaps(
1930 dynamic_common_decorations *dcd)
1932 ButtonState bs;
1933 int i;
1935 for (bs = 0; bs < BS_MaxButtonState; bs++)
1937 if (dcd->bar_pixmaps[bs].count < 1)
1939 continue;
1941 for (i = 0; i < dcd->bar_pixmaps[bs].count; i++)
1943 if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic &&
1944 dcd->bar_pixmaps[bs].bps[i].created)
1946 PDestroyFvwmPicture(
1947 dpy,
1948 dcd->bar_pixmaps[bs].bps[i].
1949 mp_created_pic);
1951 else if (dcd->bar_pixmaps[bs].bps[i].p != None &&
1952 dcd->bar_pixmaps[bs].bps[i].created)
1954 XFreePixmap(
1955 dpy, dcd->bar_pixmaps[bs].bps[i].p);
1958 free(dcd->bar_pixmaps[bs].bps);
1964 * MultiPixmap (aka, fancy title bar) (tril@igs.net)
1967 #define TBMP_HAS_PART(p, pm, acs, sf) \
1968 (pm[p] || acs[p].cs >= 0 || (sf & (1 << p)))
1970 /* Tile or stretch src into dest, starting at the given location and
1971 * continuing for the given width and height. This is a utility function used
1972 * by border_mp_draw_mp_titlebar. (tril@igs.net) */
1973 static void border_mp_render_into_pixmap(
1974 titlebar_descr *td, common_decorations_type *cd, FvwmPicture **src,
1975 FvwmAcs *acs, Pixel *pixels, unsigned short solid_flags,
1976 unsigned short stretch_flags, int part, Pixmap dest, Window w,
1977 rectangle *full_g, rectangle *title_g, ButtonState bs, rectangle *g)
1979 int x = 0;
1980 int y = 0;
1981 pixmap_background_type bg;
1982 rectangle dest_g;
1983 dynamic_common_decorations *dcd;
1985 dcd = &cd->dynamic_cd;
1986 /* setup some default */
1987 bg.pixmap.fra.mask = 0;
1988 bg.pixmap.flags.is_stretched = 0;
1989 bg.pixmap.flags.is_tiled = 0;
1990 bg.flags.use_pixmap = 1;
1991 bg.pixmap.p = bg.pixmap.alpha = bg.pixmap.shape = None;
1992 bg.pixmap.g.x = 0;
1993 bg.pixmap.g.y = 0;
1994 dest_g.width = g->width + g->x;
1995 dest_g.height = g->height + g->y;
1996 dest_g.x = g->x;
1997 dest_g.y = g->y;
1999 if (solid_flags & (1 << part))
2001 bg.flags.use_pixmap = 0;
2002 bg.pixel = pixels[part];
2003 border_fill_pixmap_background(dest, &dest_g, &bg, cd);
2004 return;
2006 else if (acs[part].cs >= 0)
2008 Pixmap p = None;
2010 bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
2011 bg.pixmap.fra.added_alpha_percent = acs[part].alpha_percent;
2012 if (CSET_IS_TRANSPARENT_PR(acs[part].cs))
2014 return;
2016 if (CSET_IS_TRANSPARENT_ROOT(acs[part].cs))
2018 p = border_create_root_transparent_pixmap(
2019 td, w, g->width + g->x, g->height + g->y,
2020 acs[part].cs);
2021 bg.pixmap.p = p;
2022 bg.pixmap.depth = Pdepth;
2023 bg.pixmap.g.width = g->width;
2024 bg.pixmap.g.height = g->height;
2025 bg.pixmap.g.x = g->x;
2026 bg.pixmap.g.y = g->y;
2028 else if (full_g != NULL)
2030 bg.pixmap.p = border_get_bar_pixmaps(
2031 dcd, full_g, bs, acs[part].cs, NULL, part,
2032 (stretch_flags & (1 << part)), NULL);
2033 if (bg.pixmap.p)
2035 if (part != TBMP_RIGHT_MAIN)
2037 /* left buttons offset */
2038 x = title_g->x - full_g->x;
2039 y = title_g->y - full_g->y;
2041 bg.pixmap.g.width = full_g->width;
2042 bg.pixmap.g.height = full_g->height;
2043 bg.pixmap.flags.is_tiled = 1;
2044 bg.pixmap.g.x = x;
2045 bg.pixmap.g.y = y;
2046 bg.pixmap.depth = Pdepth;
2049 if (!bg.pixmap.p)
2051 int bg_w, bg_h;
2053 p = CreateBackgroundPixmap(
2054 dpy, w, g->width, g->height,
2055 &Colorset[acs[part].cs], Pdepth, Scr.BordersGC,
2056 False);
2057 bg.pixmap.p = p;
2058 GetWindowBackgroundPixmapSize(
2059 &Colorset[acs[part].cs], g->width, g->height,
2060 &bg_w, &bg_h);
2061 bg.pixmap.g.width = bg_w;
2062 bg.pixmap.g.height = bg_h;
2063 bg.pixmap.depth = Pdepth;
2064 bg.pixmap.flags.is_tiled = 1;
2066 if (bg.pixmap.p)
2068 border_fill_pixmap_background(dest, &dest_g, &bg, cd);
2070 if (p)
2072 XFreePixmap(dpy, p);
2075 else if (src[part])
2077 FvwmPicture *full_pic = NULL;
2078 Pixmap p;
2080 if (full_g != NULL)
2082 p = border_get_bar_pixmaps(
2083 dcd, full_g, bs, -1, src[part], part,
2084 (stretch_flags & (1 << part)), &full_pic);
2085 if (p && full_pic)
2087 if (part != TBMP_RIGHT_MAIN)
2089 /* left buttons offset */
2090 x = title_g->x - full_g->x;
2091 y = title_g->y - full_g->y;
2093 bg.pixmap.p = full_pic->picture;
2094 bg.pixmap.shape = full_pic->mask;
2095 bg.pixmap.alpha = full_pic->alpha;
2096 bg.pixmap.depth = full_pic->depth;
2097 bg.pixmap.g.width = full_pic->width;
2098 bg.pixmap.g.height = full_pic->height;
2099 bg.pixmap.g.x = x;
2100 bg.pixmap.g.y = y;
2103 if (!bg.pixmap.p)
2105 if (stretch_flags & (1 << part))
2107 bg.pixmap.flags.is_stretched = 1;
2109 else
2111 bg.pixmap.flags.is_tiled = 1;
2113 bg.pixmap.p = src[part]->picture;
2114 bg.pixmap.shape = src[part]->mask;
2115 bg.pixmap.alpha = src[part]->alpha;
2116 bg.pixmap.depth = src[part]->depth;
2117 bg.pixmap.g.width = src[part]->width;
2118 bg.pixmap.g.height = src[part]->height;
2119 bg.pixmap.stretch_w = dest_g.width - dest_g.x;
2120 bg.pixmap.stretch_h = dest_g.height - dest_g.y;
2123 if (bg.pixmap.p)
2125 border_fill_pixmap_background(dest, &dest_g, &bg, cd);
2129 return;
2132 static int border_mp_get_length(
2133 titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
2134 unsigned int solid_flags, int part)
2136 if (acs[part].cs >= 0 || (solid_flags & (1 << part)))
2138 /* arbitrary */
2139 if (td->has_vt)
2141 return td->bar_g.width/2;
2143 else
2145 return td->bar_g.height/2;
2148 if (pm[part] == NULL)
2150 return 0;
2152 else if (td->has_vt)
2154 return pm[part]->height;
2156 else
2158 return pm[part]->width;
2162 /* geometries relatively to the frame */
2163 static void border_mp_get_titlebar_descr(
2164 FvwmWindow *fw, titlebar_descr *td, DecorFace *df)
2166 DecorFace *tsdf;
2167 FvwmPicture **pm;
2168 FvwmAcs *acs;
2169 int add,tmpi;
2170 int left_of_text = 0;
2171 int right_of_text = 0;
2172 int left_end = 0;
2173 int right_end = 0;
2174 int before_space, after_space, under_offset, under_width;
2175 Bool has_mp = False;
2176 JustificationType just;
2177 unsigned short sf;
2178 int is_start = 0;
2180 just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
2181 /* first compute under text width */
2182 if (td->length > 0)
2184 under_width = td->length + 2*TBMP_TITLE_PADDING;
2186 else
2188 under_width = 0;
2190 if (under_width > fw->title_length)
2192 under_width = fw->title_length;
2193 td->offset = (fw->title_length - td->length) / 2;
2194 just = JUST_CENTER;
2196 for (tsdf = df; tsdf != NULL; tsdf = tsdf->next)
2198 if (tsdf->style.face_type != MultiPixmap)
2200 continue;
2202 has_mp = True;
2203 acs = tsdf->u.mp.acs;
2204 pm = tsdf->u.mp.pixmaps;
2205 sf = tsdf->u.mp.solid_flags;
2206 add = border_mp_get_length(
2207 td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
2208 if (add > left_of_text &&
2209 add + left_end + right_of_text + right_end + under_width +
2210 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2212 left_of_text = add;
2214 add = border_mp_get_length(
2215 td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
2216 if (add > right_of_text &&
2217 add + left_end + left_of_text + right_end + under_width +
2218 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2220 right_of_text = add;
2222 add = border_mp_get_length(
2223 td, pm, acs, sf, TBMP_LEFT_END);
2224 if (add > left_end &&
2225 add + right_of_text + left_of_text + right_end +
2226 under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2228 left_end = add;
2230 add = border_mp_get_length(
2231 td, pm, acs, sf, TBMP_RIGHT_END);
2232 if (add > right_end &&
2233 add + right_of_text + left_of_text + left_end +
2234 under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length)
2236 right_end = add;
2240 if (!has_mp)
2242 return;
2245 switch (just)
2247 case JUST_LEFT:
2248 is_start = 1;
2249 /* fall through */
2250 case JUST_RIGHT:
2251 if (td->has_an_upsidedown_rotation)
2253 is_start = !is_start;
2255 if (is_start)
2257 if (td->has_an_upsidedown_rotation)
2259 td->offset = max(
2260 td->offset, right_of_text + right_end +
2261 TBMP_MIN_RL_TITLE_LENGTH +
2262 TBMP_TITLE_PADDING);
2264 else
2266 td->offset = max(
2267 td->offset, left_of_text + left_end +
2268 TBMP_MIN_RL_TITLE_LENGTH +
2269 TBMP_TITLE_PADDING);
2272 else
2274 if (td->has_an_upsidedown_rotation)
2276 td->offset = min(
2277 td->offset, fw->title_length -
2278 (td->length + left_of_text +
2279 left_end + TBMP_MIN_RL_TITLE_LENGTH +
2280 TBMP_TITLE_PADDING));
2282 else
2284 td->offset = min(
2285 td->offset, fw->title_length -
2286 (td->length + right_of_text +
2287 right_end + TBMP_MIN_RL_TITLE_LENGTH +
2288 TBMP_TITLE_PADDING));
2291 break;
2292 case JUST_CENTER:
2293 default:
2294 break;
2297 under_offset = td->offset - (under_width - td->length)/2;
2298 before_space = under_offset;
2299 if (td->has_vt)
2301 after_space =
2302 td->layout.title_g.height - before_space - under_width;
2304 else
2306 after_space =
2307 td->layout.title_g.width - before_space - under_width;
2309 if (td->has_an_upsidedown_rotation)
2311 td->left_end_length = right_end;
2312 td->left_of_text_length = right_of_text;
2313 td->right_of_text_length = left_of_text;
2314 td->right_end_length = left_end;
2315 tmpi = before_space;
2316 before_space = after_space;
2317 after_space = tmpi;
2319 else
2321 td->left_end_length = left_end;
2322 td->left_of_text_length = left_of_text;
2323 td->right_of_text_length = right_of_text;
2324 td->right_end_length = right_end;
2327 if (td->has_vt)
2329 td->under_text_g.width = td->bar_g.width;
2330 td->under_text_g.height = under_width;
2331 td->under_text_g.x = 0;
2332 td->under_text_g.y = under_offset;
2334 else
2336 td->under_text_g.height = td->bar_g.height;
2337 td->under_text_g.width = under_width;
2338 td->under_text_g.x = under_offset;
2339 td->under_text_g.y = 0;
2342 /* width & height */
2343 if (td->has_vt)
2345 /* left */
2346 td->full_left_main_g.width = td->bar_g.width;
2347 td->full_left_main_g.height =
2348 before_space + td->left_buttons_g.height;
2349 td->left_main_g.width = td->bar_g.width;
2350 td->left_main_g.height = before_space;
2351 /* right */
2352 td->full_right_main_g.width = td->bar_g.width;
2353 td->full_right_main_g.height = after_space +
2354 td->right_buttons_g.height;
2355 td->right_main_g.width = td->bar_g.width;
2356 td->right_main_g.height = after_space;
2358 else
2360 /* left */
2361 td->full_left_main_g.height = td->bar_g.height;
2362 td->full_left_main_g.width =
2363 before_space + td->left_buttons_g.width;
2364 td->left_main_g.height = td->bar_g.height;
2365 td->left_main_g.width = before_space;
2366 /* right */
2367 td->full_right_main_g.height = td->bar_g.height;
2368 td->full_right_main_g.width = after_space +
2369 td->right_buttons_g.width;
2370 td->right_main_g.height = td->bar_g.height;
2371 td->right_main_g.width = after_space;
2374 /* position */
2375 if (td->has_an_upsidedown_rotation)
2377 td->full_right_main_g.x = td->bar_g.x;
2378 td->full_right_main_g.y = td->bar_g.y;
2379 td->right_main_g.x = 0;
2380 td->right_main_g.y = 0;
2382 else
2384 td->full_left_main_g.x = td->bar_g.x;
2385 td->full_left_main_g.y = td->bar_g.y;
2386 td->left_main_g.x = 0;
2387 td->left_main_g.y = 0;
2390 if (td->has_vt)
2392 if (td->has_an_upsidedown_rotation)
2394 td->full_left_main_g.x = td->bar_g.x;
2395 td->full_left_main_g.y =
2396 td->full_right_main_g.height + td->bar_g.y +
2397 td->under_text_g.height;
2398 td->left_main_g.y =
2399 td->under_text_g.y + td->under_text_g.height;
2400 td->left_main_g.x = 0;
2402 else
2404 td->full_right_main_g.x = td->bar_g.x;
2405 td->full_right_main_g.y =
2406 td->full_left_main_g.height + td->bar_g.y +
2407 td->under_text_g.height;
2408 td->right_main_g.y =
2409 td->under_text_g.y + td->under_text_g.height;
2410 td->right_main_g.x = 0;
2413 else
2415 if (td->has_an_upsidedown_rotation)
2417 td->full_left_main_g.x =
2418 td->full_right_main_g.width + td->bar_g.x +
2419 td->under_text_g.width;
2420 td->full_left_main_g.y = td->bar_g.y;
2421 td->left_main_g.x =
2422 td->under_text_g.x + td->under_text_g.width;
2423 td->left_main_g.y = 0;
2425 else
2427 td->full_right_main_g.x =
2428 td->full_left_main_g.width + td->bar_g.x +
2429 td->under_text_g.width;
2430 td->full_right_main_g.y = td->bar_g.y;
2431 td->right_main_g.x =
2432 td->under_text_g.x + td->under_text_g.width;
2433 td->right_main_g.y = 0;
2438 /* the returned geometries are relative to the titlebar (not the frame) */
2439 static void border_mp_get_extreme_geometry(
2440 titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs, unsigned short sf,
2441 rectangle *left_of_text_g, rectangle *right_of_text_g,
2442 rectangle *left_end_g, rectangle *right_end_g)
2444 int left_of_text = 0;
2445 int right_of_text = 0;
2446 int left_end = 0;
2447 int right_end = 0;
2449 left_of_text = border_mp_get_length(
2450 td, pm, acs, sf, TBMP_LEFT_OF_TEXT);
2451 left_end = border_mp_get_length(
2452 td, pm, acs, sf, TBMP_LEFT_END);
2453 right_of_text = border_mp_get_length(
2454 td, pm, acs, sf, TBMP_RIGHT_OF_TEXT);
2455 right_end = border_mp_get_length(
2456 td, pm, acs, sf, TBMP_RIGHT_END);
2458 if (left_of_text > 0 && left_of_text <= td->left_of_text_length)
2460 if (td->has_vt)
2462 left_of_text_g->y = td->under_text_g.y - left_of_text;
2463 left_of_text_g->x = 0;
2464 left_of_text_g->height = left_of_text;
2465 left_of_text_g->width = td->bar_g.width;
2467 else
2469 left_of_text_g->x = td->under_text_g.x - left_of_text;
2470 left_of_text_g->y = 0;
2471 left_of_text_g->width = left_of_text;
2472 left_of_text_g->height = td->bar_g.height;
2475 else
2477 left_of_text_g->x = 0;
2478 left_of_text_g->y = 0;
2479 left_of_text_g->width = 0;
2480 left_of_text_g->height = 0;
2483 if (right_of_text > 0 && right_of_text <= td->right_of_text_length)
2485 if (td->has_vt)
2487 right_of_text_g->y =
2488 td->under_text_g.y + td->under_text_g.height;
2489 right_of_text_g->x = 0;
2490 right_of_text_g->height = right_of_text;
2491 right_of_text_g->width = td->bar_g.width;
2493 else
2495 right_of_text_g->x =
2496 td->under_text_g.x + td->under_text_g.width;
2497 right_of_text_g->y = 0;
2498 right_of_text_g->width = right_of_text;
2499 right_of_text_g->height = td->bar_g.height;
2502 else
2504 right_of_text_g->x = 0;
2505 right_of_text_g->y = 0;
2506 right_of_text_g->width = 0;
2507 right_of_text_g->height = 0;
2510 if (left_end > 0 && left_end <= td->left_end_length)
2512 if (td->has_vt)
2514 left_end_g->y = 0;
2515 left_end_g->x = 0;
2516 left_end_g->height = left_end;
2517 left_end_g->width = td->bar_g.width;
2519 else
2521 left_end_g->x = 0;
2522 left_end_g->y = 0;
2523 left_end_g->width = left_end;
2524 left_end_g->height = td->bar_g.height;
2527 else
2529 left_end_g->x = 0;
2530 left_end_g->y = 0;
2531 left_end_g->width = 0;
2532 left_end_g->height = 0;
2535 if (right_end > 0 && right_end <= td->right_end_length)
2537 if (td->has_vt)
2539 right_end_g->y =
2540 td->layout.title_g.height - right_end;
2541 right_end_g->x = 0;
2542 right_end_g->height = right_end;
2543 right_end_g->width = td->bar_g.width;
2545 else
2547 right_end_g->x =
2548 td->layout.title_g.width - right_end;
2549 right_end_g->y = 0;
2550 right_end_g->width = right_end;
2551 right_end_g->height = td->bar_g.height;
2554 else
2556 right_end_g->x = 0;
2557 right_end_g->y = 0;
2558 right_end_g->width = 0;
2559 right_end_g->height = 0;
2562 return;
2565 static Bool border_mp_get_use_title_style_parts_and_geometry(
2566 titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs,
2567 unsigned short sf, int is_left, rectangle *g, int *part)
2569 rectangle *tmp_g = NULL;
2570 Bool g_ok = True;
2572 if (is_left && TBMP_HAS_PART(TBMP_LEFT_BUTTONS, pm, acs, sf))
2574 *part = TBMP_LEFT_BUTTONS;
2575 tmp_g = &td->left_buttons_g;
2577 else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_BUTTONS, pm, acs, sf))
2579 *part = TBMP_RIGHT_BUTTONS;
2580 tmp_g = &td->right_buttons_g;
2582 else if (is_left && TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, sf))
2584 *part = TBMP_LEFT_MAIN;
2585 tmp_g = &td->full_left_main_g;
2587 else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, sf))
2589 *part = TBMP_RIGHT_MAIN;
2590 tmp_g = &td->full_right_main_g;
2592 else if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, sf))
2594 *part = TBMP_MAIN;
2595 tmp_g = &(td->bar_g);
2597 else
2599 *part = TBMP_NONE;
2601 if (g && tmp_g)
2603 g->x = tmp_g->x;
2604 g->y = tmp_g->y;
2605 g->width = tmp_g->width;
2606 g->height = tmp_g->height;
2607 g_ok = True;
2610 return g_ok;
2613 /* Redraws multi-pixmap titlebar (tril@igs.net) */
2614 static void border_mp_draw_mp_titlebar(
2615 FvwmWindow *fw, titlebar_descr *td, DecorFace *df, Pixmap dest_pix,
2616 Window w)
2618 FvwmPicture **pm;
2619 FvwmAcs *acs;
2620 Pixel *pixels;
2621 unsigned short solid_flags;
2622 unsigned short stretch_flags;
2623 rectangle tmp_g, left_of_text_g,left_end_g,right_of_text_g,right_end_g;
2624 dynamic_common_decorations *dcd;
2625 ButtonState bs;
2627 dcd = &(td->cd->dynamic_cd);
2628 bs = td->tbstate.tstate;
2629 pm = df->u.mp.pixmaps;
2630 acs = df->u.mp.acs;
2631 pixels = df->u.mp.pixels;
2632 stretch_flags = df->u.mp.stretch_flags;
2633 solid_flags = df->u.mp.solid_flags;
2634 tmp_g.x = 0;
2635 tmp_g.y = 0;
2636 tmp_g.width = td->layout.title_g.width;
2637 tmp_g.height = td->layout.title_g.height;
2639 if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, solid_flags))
2641 border_mp_render_into_pixmap(
2642 td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2643 TBMP_MAIN, dest_pix, w, &td->bar_g, &td->layout.title_g,
2644 bs, &tmp_g);
2646 else if (td->length <= 0)
2648 border_mp_render_into_pixmap(
2649 td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2650 TBMP_LEFT_MAIN, dest_pix, w, NULL, &td->layout.title_g,
2651 bs, &tmp_g);
2654 border_mp_get_extreme_geometry(
2655 td, pm, acs, solid_flags, &left_of_text_g, &right_of_text_g,
2656 &left_end_g, &right_end_g);
2658 if (td->length > 0)
2660 if (TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, solid_flags) &&
2661 td->left_main_g.width > 0 && td->left_main_g.height > 0)
2663 border_mp_render_into_pixmap(
2664 td, td->cd, pm, acs, pixels, solid_flags,
2665 stretch_flags, TBMP_LEFT_MAIN, dest_pix, w,
2666 &td->full_left_main_g, &td->layout.title_g, bs,
2667 &td->left_main_g);
2669 if (TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, solid_flags) &&
2670 td->right_main_g.width > 0 && td->right_main_g.height > 0)
2672 border_mp_render_into_pixmap(
2673 td, td->cd, pm, acs, pixels, solid_flags,
2674 stretch_flags, TBMP_RIGHT_MAIN, dest_pix, w,
2675 &td->full_right_main_g, &td->layout.title_g, bs,
2676 &td->right_main_g);
2678 if (TBMP_HAS_PART(TBMP_UNDER_TEXT, pm, acs, solid_flags) &&
2679 td->under_text_g.width > 0 && td->under_text_g.height > 0)
2681 border_mp_render_into_pixmap(
2682 td, td->cd, pm, acs, pixels, solid_flags,
2683 stretch_flags, TBMP_UNDER_TEXT, dest_pix, w,
2684 NULL, &td->layout.title_g, bs,
2685 &td->under_text_g);
2687 if (left_of_text_g.width > 0 && left_of_text_g.height > 0)
2689 border_mp_render_into_pixmap(
2690 td, td->cd, pm, acs, pixels, solid_flags,
2691 stretch_flags, TBMP_LEFT_OF_TEXT, dest_pix, w,
2692 NULL, &td->layout.title_g, bs, &left_of_text_g);
2694 if (right_of_text_g.width > 0 && right_of_text_g.height > 0)
2696 border_mp_render_into_pixmap(
2697 td, td->cd, pm, acs, pixels, solid_flags,
2698 stretch_flags, TBMP_RIGHT_OF_TEXT, dest_pix, w,
2699 NULL, &td->layout.title_g, bs, &right_of_text_g);
2702 if (left_end_g.width > 0 && left_end_g.height > 0)
2704 border_mp_render_into_pixmap(
2705 td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2706 TBMP_LEFT_END, dest_pix, w, NULL, &td->layout.title_g,
2707 bs, &left_end_g);
2709 if (right_end_g.width > 0 && right_end_g.height > 0)
2711 border_mp_render_into_pixmap(
2712 td, td->cd, pm, acs, pixels, solid_flags, stretch_flags,
2713 TBMP_RIGHT_END, dest_pix, w, NULL, &td->layout.title_g,
2714 bs, &right_end_g);
2717 return;
2722 * draw title bar and buttons
2725 static void border_draw_decor_to_pixmap(
2726 FvwmWindow *fw, Pixmap dest_pix, Window w,
2727 pixmap_background_type *solid_bg, rectangle *w_g,
2728 DecorFace *df, titlebar_descr *td, ButtonState bs,
2729 int use_title_style, int is_toggled, int left1right0)
2731 register DecorFaceType type = DFS_FACE_TYPE(df->style);
2732 pixmap_background_type bg;
2733 rectangle dest_g;
2734 FvwmPicture *p;
2735 int width,height;
2736 int border;
2737 int lr_just, tb_just;
2738 common_decorations_type *cd;
2740 cd = td->cd;
2741 /* setup some default */
2742 bg.pixmap.fra.mask = 0;
2743 bg.pixmap.flags.is_stretched = 0;
2744 bg.pixmap.flags.is_tiled = 0;
2745 bg.flags.use_pixmap = 0;
2746 bg.pixmap.g.x = 0;
2747 bg.pixmap.g.y = 0;
2749 if (DFS_BUTTON_RELIEF(df->style) == DFS_BUTTON_IS_FLAT)
2751 border = 0;
2753 else
2755 border = HAS_MWM_BORDER(fw) ? 1 : 2;
2757 dest_g.width = w_g->width;
2758 dest_g.height = w_g->height;
2759 dest_g.x = border;
2760 dest_g.y = border;
2762 switch (type)
2764 case SimpleButton:
2765 /* do nothing */
2766 break;
2767 case SolidButton:
2768 /* overwrite with the default background */
2769 dest_g.x = 0;
2770 dest_g.y = 0;
2771 border_fill_pixmap_background(dest_pix, &dest_g, solid_bg, cd);
2772 break;
2773 case VectorButton:
2774 case DefaultVectorButton:
2775 border_draw_vector_to_pixmap(
2776 dest_pix, cd, is_toggled, &df->u.vector, w_g);
2777 break;
2778 case MiniIconButton:
2779 case PixmapButton:
2780 case ShrunkPixmapButton:
2781 case StretchedPixmapButton:
2782 if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
2784 break;
2786 if (FMiniIconsSupported && type == MiniIconButton)
2788 if (!fw->mini_icon)
2790 break;
2792 p = fw->mini_icon;
2793 if (cd->cs >= 0)
2795 bg.pixmap.fra.mask |= FRAM_HAVE_ICON_CSET;
2796 bg.pixmap.fra.colorset = &Colorset[cd->cs];
2799 else
2801 p = df->u.p;
2803 width = p->width;
2804 height = p->height;
2805 if ((type == ShrunkPixmapButton || type == MiniIconButton) &&
2806 (p->width > w_g->width - 2*border ||
2807 p->height > w_g->height - 2*border))
2809 /* do so that the picture fit into the destination */
2810 bg.pixmap.stretch_w = width =
2811 min(w_g->width - 2*border, p->width);
2812 bg.pixmap.stretch_h = height =
2813 min(w_g->height - 2*border, p->height);
2814 bg.pixmap.flags.is_stretched = 1;
2816 else if (type == StretchedPixmapButton &&
2817 (p->width < w_g->width - 2*border ||
2818 p->height < w_g->height - 2*border))
2820 /* do so that the picture fit into the destination */
2821 bg.pixmap.stretch_w = width =
2822 max(w_g->width - 2*border, p->width);
2823 bg.pixmap.stretch_h = height =
2824 max(w_g->height - 2*border, p->height);
2825 bg.pixmap.flags.is_stretched = 1;
2827 lr_just = DFS_H_JUSTIFICATION(df->style);
2828 tb_just = DFS_V_JUSTIFICATION(df->style);
2829 if (!td->td_is_rotated && fw->title_text_rotation != ROTATION_0)
2831 if (fw->title_text_rotation == ROTATION_180)
2833 switch (lr_just)
2835 case JUST_LEFT:
2836 lr_just = JUST_RIGHT;
2837 break;
2838 case JUST_RIGHT:
2839 lr_just = JUST_LEFT;
2840 break;
2841 case JUST_CENTER:
2842 default:
2843 break;
2845 switch (tb_just)
2847 case JUST_TOP:
2848 tb_just = JUST_BOTTOM;
2849 break;
2850 case JUST_BOTTOM:
2851 tb_just = JUST_TOP;
2852 break;
2853 case JUST_CENTER:
2854 default:
2855 break;
2858 else if (fw->title_text_rotation == ROTATION_90)
2860 switch (lr_just)
2862 case JUST_LEFT:
2863 tb_just = JUST_TOP;
2864 break;
2865 case JUST_RIGHT:
2866 tb_just = JUST_BOTTOM;
2867 break;
2868 case JUST_CENTER:
2869 default:
2870 tb_just = JUST_CENTER;
2871 break;
2873 switch (DFS_V_JUSTIFICATION(df->style))
2875 case JUST_TOP:
2876 lr_just = JUST_RIGHT;
2877 break;
2878 case JUST_BOTTOM:
2879 lr_just = JUST_LEFT;
2880 break;
2881 case JUST_CENTER:
2882 default:
2883 lr_just = JUST_CENTER;
2884 break;
2887 else if (fw->title_text_rotation == ROTATION_270)
2889 switch (lr_just)
2891 case JUST_LEFT:
2892 tb_just = JUST_BOTTOM;
2893 break;
2894 case JUST_RIGHT:
2895 tb_just = JUST_TOP;
2896 break;
2897 case JUST_CENTER:
2898 default:
2899 tb_just = JUST_CENTER;
2900 break;
2902 switch (DFS_V_JUSTIFICATION(df->style))
2904 case JUST_TOP:
2905 lr_just = JUST_LEFT;
2906 break;
2907 case JUST_BOTTOM:
2908 lr_just = JUST_RIGHT;
2909 break;
2910 case JUST_CENTER:
2911 default:
2912 lr_just = JUST_CENTER;
2913 break;
2917 switch (lr_just)
2919 case JUST_LEFT:
2920 dest_g.x = border;
2921 break;
2922 case JUST_RIGHT:
2923 dest_g.x = (int)(w_g->width - width - border);
2924 break;
2925 case JUST_CENTER:
2926 default:
2927 /* round down */
2928 dest_g.x = (int)(w_g->width - width) / 2;
2929 break;
2931 switch (tb_just)
2933 case JUST_TOP:
2934 dest_g.y = border;
2935 break;
2936 case JUST_BOTTOM:
2937 dest_g.y = (int)(w_g->height - height - border);
2938 break;
2939 case JUST_CENTER:
2940 default:
2941 /* round down */
2942 dest_g.y = (int)(w_g->height - height) / 2;
2943 break;
2945 if (dest_g.x < border)
2947 dest_g.x = border;
2949 if (dest_g.y < border)
2951 dest_g.y = border;
2953 bg.flags.use_pixmap = 1;
2954 bg.pixmap.p = p->picture;
2955 bg.pixmap.shape = p->mask;
2956 bg.pixmap.alpha = p->alpha;
2957 bg.pixmap.depth = p->depth;
2958 bg.pixmap.g.width = p->width;
2959 bg.pixmap.g.height = p->height;
2960 border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
2961 break;
2962 case TiledPixmapButton:
2963 case AdjustedPixmapButton:
2964 if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0)
2966 break;
2968 p = df->u.p;
2969 if (type == TiledPixmapButton)
2971 bg.pixmap.flags.is_tiled = 1;
2973 else
2975 bg.pixmap.stretch_w = width = w_g->width - 2*dest_g.x;
2976 bg.pixmap.stretch_h = height = w_g->height - 2*dest_g.y;
2977 bg.pixmap.flags.is_stretched = 1;
2979 bg.flags.use_pixmap = 1;
2980 bg.pixmap.p = p->picture;
2981 bg.pixmap.shape = p->mask;
2982 bg.pixmap.alpha = p->alpha;
2983 bg.pixmap.depth = p->depth;
2984 bg.pixmap.g.width = p->width;
2985 bg.pixmap.g.height = p->height;
2986 border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
2987 break;
2988 case MultiPixmap: /* for UseTitleStyle only */
2990 int is_left = left1right0;
2991 int part = TBMP_NONE;
2992 int ap, cs;
2993 unsigned int stretch;
2994 Pixmap tmp = None;
2995 FvwmPicture *full_pic = NULL;
2996 rectangle g;
2997 dynamic_common_decorations *dcd = &(cd->dynamic_cd);
2998 FvwmPicture **pm;
2999 FvwmAcs *acs;
3000 Pixel *pixels;
3001 unsigned short sf;
3003 pm = df->u.mp.pixmaps;
3004 acs = df->u.mp.acs;
3005 pixels = df->u.mp.pixels;
3006 sf = df->u.mp.solid_flags;
3007 if (!border_mp_get_use_title_style_parts_and_geometry(
3008 td, pm, acs, sf, is_left, &g, &part))
3010 g.width = 0;
3011 g.height = 0;
3012 g.x = 0;
3013 g.y = 0;
3016 if (part == TBMP_NONE)
3018 break;
3021 if (sf & (1 << part))
3023 bg.flags.use_pixmap = 0;
3024 bg.pixel = pixels[part];
3025 border_fill_pixmap_background(
3026 dest_pix, &dest_g, &bg, cd);
3027 break;
3029 cs = acs[part].cs;
3030 ap = acs[part].alpha_percent;
3031 if (CSET_IS_TRANSPARENT_PR(cs))
3033 break;
3035 if (cs >= 0)
3037 bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
3038 bg.pixmap.fra.added_alpha_percent = ap;
3040 stretch = !!(df->u.mp.stretch_flags & (1 << part));
3041 bg.flags.use_pixmap = 1;
3042 dest_g.x = 0;
3043 dest_g.y = 0;
3045 if (cs >= 0 && use_title_style && g.width > 0 && g.height > 0 &&
3046 !CSET_IS_TRANSPARENT_ROOT(cs) &&
3047 (bg.pixmap.p = border_get_bar_pixmaps(
3048 dcd, &g, bs, cs, NULL, part, stretch, NULL)) != None)
3050 bg.pixmap.g.width = g.width;
3051 bg.pixmap.g.height = g.height;
3052 bg.pixmap.flags.is_tiled = 1;
3053 bg.pixmap.g.x = w_g->x - g.x;
3054 bg.pixmap.g.y = w_g->y - g.y;
3055 bg.pixmap.shape = None;
3056 bg.pixmap.alpha = None;
3057 bg.pixmap.depth = Pdepth;
3059 else if (CSET_IS_TRANSPARENT_ROOT(cs))
3061 tmp = border_create_root_transparent_pixmap(
3062 td, w, w_g->width, w_g->height, cs);
3063 bg.pixmap.p = tmp;
3064 bg.pixmap.g.width = w_g->width;
3065 bg.pixmap.g.height = w_g->height;
3066 bg.pixmap.shape = None;
3067 bg.pixmap.alpha = None;
3068 bg.pixmap.depth = Pdepth;
3070 else if (cs >= 0)
3072 int bg_w, bg_h;
3074 tmp = CreateBackgroundPixmap(
3075 dpy, w, w_g->width,
3076 w_g->height, &Colorset[cs],
3077 Pdepth, Scr.BordersGC, False);
3078 bg.pixmap.p = tmp;
3079 GetWindowBackgroundPixmapSize(
3080 &Colorset[cs], w_g->width,
3081 w_g->height, &bg_w, &bg_h);
3082 bg.pixmap.g.width = bg_w;
3083 bg.pixmap.g.height = bg_h;
3084 bg.pixmap.shape = None;
3085 bg.pixmap.alpha = None;
3086 bg.pixmap.depth = Pdepth;
3087 bg.pixmap.flags.is_tiled = 1;
3089 else if (pm[part] && g.width > 0 && g.height > 0 &&
3090 border_get_bar_pixmaps(
3091 dcd, &g, bs, -1, pm[part], part, stretch,
3092 &full_pic) != None && full_pic)
3094 bg.pixmap.p = full_pic->picture;
3095 bg.pixmap.shape = full_pic->mask;
3096 bg.pixmap.alpha = full_pic->alpha;
3097 bg.pixmap.depth = full_pic->depth;
3098 bg.pixmap.g.width = full_pic->width;
3099 bg.pixmap.g.height = full_pic->height;
3100 bg.pixmap.g.x = w_g->x - g.x;
3101 bg.pixmap.g.y = w_g->y - g.y;
3103 else if (pm[part])
3105 p = pm[part];
3106 if (df->u.mp.stretch_flags & (1 << part))
3108 bg.pixmap.flags.is_stretched = 1;
3110 else
3112 bg.pixmap.flags.is_tiled = 1;
3114 bg.pixmap.p = p->picture;
3115 bg.pixmap.shape = p->mask;
3116 bg.pixmap.alpha = p->alpha;
3117 bg.pixmap.depth = p->depth;
3118 bg.pixmap.g.width = p->width;
3119 bg.pixmap.g.height = p->height;
3120 bg.pixmap.stretch_w = dest_g.width - dest_g.x;
3121 bg.pixmap.stretch_h = dest_g.height - dest_g.y;
3123 else
3125 /* should not happen */
3126 return;
3128 if (bg.pixmap.p != None)
3130 border_fill_pixmap_background(
3131 dest_pix, &dest_g, &bg, cd);
3133 if (tmp != None)
3135 XFreePixmap(dpy, tmp);
3137 break;
3139 case ColorsetButton:
3141 colorset_t *cs_t = &Colorset[df->u.acs.cs];
3142 int cs = df->u.acs.cs;
3143 Pixmap tmp = None;
3144 int bg_w, bg_h;
3146 if (CSET_IS_TRANSPARENT_PR(cs))
3148 break;
3150 dest_g.x = 0;
3151 dest_g.y = 0;
3152 if (use_title_style &&
3153 !CSET_IS_TRANSPARENT_ROOT(cs) &&
3154 (bg.pixmap.p = border_get_bar_pixmaps(
3155 &(cd->dynamic_cd), &(td->bar_g), bs, cs, NULL,
3156 TBMP_NONE, 0, NULL))
3157 != None)
3159 bg.pixmap.g.width = td->bar_g.width;
3160 bg.pixmap.g.height = td->bar_g.height;
3161 bg.pixmap.g.x = w_g->x - td->bar_g.x;
3162 bg.pixmap.g.y = w_g->y - td->bar_g.y;
3164 else if (CSET_IS_TRANSPARENT_ROOT(cs))
3166 tmp = border_create_root_transparent_pixmap(
3167 td, w, w_g->width, w_g->height, cs);
3168 if (tmp == None)
3170 break;
3172 bg.pixmap.p = tmp;
3173 bg.pixmap.g.width = w_g->width;
3174 bg.pixmap.g.height = w_g->height;
3175 bg.pixmap.shape = None;
3176 bg.pixmap.alpha = None;
3177 bg.pixmap.depth = Pdepth;
3179 else
3181 tmp = CreateBackgroundPixmap(
3182 dpy, w, w_g->width, w_g->height,
3183 cs_t, Pdepth, Scr.BordersGC, False);
3184 if (tmp == None)
3186 break;
3188 bg.pixmap.p = tmp;
3189 GetWindowBackgroundPixmapSize(
3190 cs_t, w_g->width, w_g->height,
3191 &bg_w, &bg_h);
3192 bg.pixmap.g.width = bg_w;
3193 bg.pixmap.g.height = bg_h;
3194 bg.pixmap.g.x = 0;
3195 bg.pixmap.g.y = 0;
3197 bg.flags.use_pixmap = 1;
3198 bg.pixmap.shape = None;
3199 bg.pixmap.alpha = None;
3200 bg.pixmap.depth = Pdepth;
3201 bg.pixmap.flags.is_tiled = 1;
3202 bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA;
3203 bg.pixmap.fra.added_alpha_percent = df->u.acs.alpha_percent;
3204 border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd);
3205 if (tmp)
3207 XFreePixmap(dpy, tmp);
3209 break;
3211 case GradientButton:
3212 /* draw the gradient into the pixmap */
3213 CreateGradientPixmap(
3214 dpy, dest_pix, Scr.TransMaskGC,
3215 df->u.grad.gradient_type, 0, 0, df->u.grad.npixels,
3216 df->u.grad.xcs, df->u.grad.do_dither,
3217 &df->u.grad.d_pixels, &df->u.grad.d_npixels,
3218 dest_pix, 0, 0, w_g->width, w_g->height, NULL);
3220 break;
3222 default:
3223 fvwm_msg(ERR, "DrawButton", "unknown button type: %i", type);
3224 break;
3227 return;
3230 static void border_set_button_pixmap(
3231 FvwmWindow *fw, titlebar_descr *td, int button, Pixmap *dest_pix,
3232 Window w)
3234 pixmap_background_type bg;
3235 unsigned int mask;
3236 int is_left_button;
3237 int do_reverse_relief;
3238 ButtonState bs;
3239 DecorFace *df;
3240 rectangle *button_g;
3241 GC rgc;
3242 GC sgc;
3243 Bool free_bg_pixmap = False;
3244 rectangle pix_g;
3246 /* prepare variables */
3247 mask = (1 << button);
3248 if (td->has_an_upsidedown_rotation)
3250 is_left_button = (button & 1);
3252 else
3254 is_left_button = !(button & 1);
3256 button_g = &td->layout.button_g[button];
3257 bs = td->tbstate.bstate[button];
3258 df = &TB_STATE(GetDecor(fw, buttons[button]))[bs];
3259 rgc = td->cd->relief_gc;
3260 sgc = td->cd->shadow_gc;
3261 /* prepare background, either from the window colour or from the
3262 * border style */
3263 if (!DFS_USE_BORDER_STYLE(df->style))
3265 /* fill with the button background colour */
3266 bg.flags.use_pixmap = 0;
3267 bg.pixel = td->cd->back_color;
3268 pix_g.x = 0;
3269 pix_g.y = 0;
3270 pix_g.width = button_g->width;
3271 pix_g.height = button_g->height;
3272 border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
3274 else
3276 /* draw pixmap background inherited from border style */
3277 rectangle relative_g;
3279 relative_g.width = td->frame_g.width;
3280 relative_g.height = td->frame_g.height;
3281 relative_g.x = button_g->x;
3282 relative_g.y = button_g->y;
3283 border_get_border_background(
3284 &bg, td->cd, button_g, &relative_g, &free_bg_pixmap, w);
3285 bg.pixmap.g.x = 0;
3286 bg.pixmap.g.y = 0;
3287 /* set the geometry for drawing the Tiled pixmap;
3288 * FIXME: maybe add the relief as offset? */
3289 pix_g.x = 0;
3290 pix_g.y = 0;
3291 pix_g.width = button_g->width;
3292 pix_g.height = button_g->height;
3293 border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd);
3294 if (free_bg_pixmap && bg.pixmap.p)
3296 XFreePixmap(dpy, bg.pixmap.p);
3300 /* handle title style */
3301 if (DFS_USE_TITLE_STYLE(df->style))
3303 /* draw background inherited from title style */
3304 DecorFace *tsdf;
3305 Pixmap tmp;
3307 if (td->draw_rotation != ROTATION_0)
3309 tmp = CreateRotatedPixmap(
3310 dpy, *dest_pix,
3311 td->layout.button_g[button].width,
3312 td->layout.button_g[button].height,
3313 Pdepth, Scr.BordersGC, td->restore_rotation);
3314 XFreePixmap(dpy, *dest_pix);
3315 *dest_pix = tmp;
3316 border_rotate_titlebar_descr(fw, td);
3317 button_g = &td->layout.button_g[button];
3318 is_left_button = !(button & 1);
3320 for (tsdf = &TB_STATE(GetDecor(fw, titlebar))[bs]; tsdf != NULL;
3321 tsdf = tsdf->next)
3323 bg.pixel = tsdf->u.back;
3324 border_draw_decor_to_pixmap(
3325 fw, *dest_pix, w, &bg, button_g, tsdf, td,
3326 bs, True, (td->tbstate.toggled_bmask & mask),
3327 is_left_button);
3329 if (td->draw_rotation != ROTATION_0)
3331 tmp = CreateRotatedPixmap(
3332 dpy, *dest_pix,
3333 td->layout.button_g[button].width,
3334 td->layout.button_g[button].height,
3335 Pdepth, Scr.BordersGC, td->draw_rotation);
3336 XFreePixmap(dpy, *dest_pix);
3337 *dest_pix = tmp;
3338 border_rotate_titlebar_descr(fw, td);
3339 button_g = &td->layout.button_g[button];
3340 if (td->has_an_upsidedown_rotation)
3342 is_left_button = (button & 1);
3344 else
3346 is_left_button = !(button & 1);
3350 /* handle button style */
3351 for ( ; df; df = df->next)
3353 /* draw background from button style */
3354 bg.pixel = df->u.back;
3355 border_draw_decor_to_pixmap(
3356 fw, *dest_pix, w, &bg, button_g, df, td, bs, False,
3357 (td->tbstate.toggled_bmask & mask), is_left_button);
3359 /* draw the button relief */
3360 do_reverse_relief = !!(td->tbstate.pressed_bmask & mask);
3361 switch (DFS_BUTTON_RELIEF(
3362 TB_STATE(GetDecor(fw, buttons[button]))[bs].style))
3364 case DFS_BUTTON_IS_SUNK:
3365 do_reverse_relief ^= 1;
3366 /* fall through*/
3367 case DFS_BUTTON_IS_UP:
3368 do_relieve_rectangle(
3369 dpy, *dest_pix, 0, 0, button_g->width - 1,
3370 button_g->height - 1,
3371 (do_reverse_relief) ? sgc : rgc,
3372 (do_reverse_relief) ? rgc : sgc,
3373 td->cd->relief_width, True);
3374 break;
3375 default:
3376 /* flat */
3377 break;
3380 return;
3383 static void border_draw_one_button(
3384 FvwmWindow *fw, titlebar_descr *td, int button)
3386 Pixmap p;
3388 /* make a pixmap */
3389 if (td->layout.button_g[button].x < 0 ||
3390 td->layout.button_g[button].y < 0)
3392 return;
3395 p = border_create_decor_pixmap(td->cd, &(td->layout.button_g[button]));
3396 /* set the background tile */
3397 border_set_button_pixmap(fw, td, button, &p, FW_W_BUTTON(fw, button));
3398 /* apply the pixmap and destroy it */
3399 border_set_part_background(FW_W_BUTTON(fw, button), p);
3400 XFreePixmap(dpy, p);
3401 if ((td->tbstate.clear_bmask & (1 << button)) != 0)
3403 XClearWindow(dpy, FW_W_BUTTON(fw, button));
3406 return;
3409 static void border_draw_title_stick_lines(
3410 FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3411 Pixmap dest_pix)
3413 int i;
3414 int num;
3415 int min;
3416 int max;
3417 int left_x;
3418 int left_w;
3419 int right_x;
3420 int right_w;
3421 int under_text_length = 0;
3422 int under_text_offset = 0;
3423 int right_length = 0;
3424 int left_length = 0;
3425 rotation_t rotation;
3427 if (!( (HAS_STICKY_STIPPLED_TITLE(fw) &&
3428 (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)))
3429 || HAS_STIPPLED_TITLE(fw)))
3431 return;
3433 if (td->td_is_rotated)
3435 rotation = td->restore_rotation;
3437 else
3439 rotation = ROTATION_0;
3441 if (td->has_vt && td->under_text_g.height > 0)
3443 under_text_length = td->under_text_g.height;
3444 under_text_offset = td->under_text_g.y;
3445 left_length = td->left_main_g.height - td->left_of_text_length
3446 - td->left_end_length;
3447 right_length = td->right_main_g.height -
3448 td->right_of_text_length - td->right_end_length;
3451 else if (!td->has_vt && td->under_text_g.width > 0)
3453 under_text_length = td->under_text_g.width;
3454 under_text_offset = td->under_text_g.x;
3455 left_length = td->left_main_g.width - td->left_of_text_length
3456 - td->left_end_length;
3457 right_length = td->right_main_g.width -
3458 td->right_of_text_length - td->right_end_length;
3461 /* If the window is sticky either across pages or
3462 * desks and it has a stippled title, but nothing for
3463 * sticky_stippled_title, then don't bother drawing them, just
3464 * return immediately. -- Thomas Adam
3466 if ( (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)) &&
3467 (!HAS_STICKY_STIPPLED_TITLE(fw) && HAS_STIPPLED_TITLE(fw)) )
3469 return;
3472 num = (int)(fw->title_thickness / WINDOW_TITLE_STICK_VERT_DIST / 2) *
3473 2 - 1;
3474 min = fw->title_thickness / 2 - num * 2 + 1;
3475 max = fw->title_thickness / 2 + num * 2 -
3476 WINDOW_TITLE_STICK_VERT_DIST + 1;
3477 left_x = WINDOW_TITLE_STICK_OFFSET + td->left_end_length;
3478 left_w = ((under_text_length == 0)? td->offset:under_text_offset)
3479 - left_x - WINDOW_TITLE_TO_STICK_GAP - td->left_of_text_length;
3480 right_x = ((under_text_length == 0)?
3481 td->offset + td->length :
3482 under_text_offset + under_text_length)
3483 + td->right_of_text_length + WINDOW_TITLE_TO_STICK_GAP - 1;
3484 right_w = fw->title_length - right_x - WINDOW_TITLE_STICK_OFFSET
3485 - td->right_end_length;
3486 /* an odd number of lines every WINDOW_TITLE_STICK_VERT_DIST pixels */
3487 if (left_w < WINDOW_TITLE_STICK_MIN_WIDTH)
3489 left_x = td->left_end_length +
3490 ((left_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
3491 (left_length - WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
3492 left_w = WINDOW_TITLE_STICK_MIN_WIDTH;
3494 if (right_w < WINDOW_TITLE_STICK_MIN_WIDTH)
3496 right_w = WINDOW_TITLE_STICK_MIN_WIDTH;
3497 right_x = fw->title_length - WINDOW_TITLE_STICK_MIN_WIDTH - 1
3498 - td->right_end_length -
3499 ((right_length > WINDOW_TITLE_STICK_MIN_WIDTH)?
3500 (right_length -
3501 WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0);
3503 for (i = min; i <= max; i += WINDOW_TITLE_STICK_VERT_DIST)
3505 if (left_w > 0)
3507 do_relieve_rectangle_with_rotation(
3508 dpy, dest_pix,
3509 SWAP_ARGS(td->has_vt, left_x, i),
3510 SWAP_ARGS(td->has_vt, left_w, 1),
3511 tdd->sgc, tdd->rgc, 1, False, rotation);
3513 if (right_w > 0)
3515 do_relieve_rectangle_with_rotation(
3516 dpy, dest_pix,
3517 SWAP_ARGS(td->has_vt, right_x, i),
3518 SWAP_ARGS(td->has_vt, right_w, 1),
3519 tdd->sgc, tdd->rgc, 1, False, rotation);
3523 return;
3526 static void border_draw_title_mono(
3527 FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3528 FlocaleWinString *fstr, Pixmap dest_pix)
3530 int has_vt;
3532 has_vt = HAS_VERTICAL_TITLE(fw);
3533 XFillRectangle(
3534 dpy, dest_pix, td->cd->relief_gc,
3535 td->offset - 2, 0, td->length+4, fw->title_thickness);
3536 if (fw->visible_name != (char *)NULL)
3538 FlocaleDrawString(dpy, fw->title_font, fstr, 0);
3540 /* for mono, we clear an area in the title bar where the window
3541 * title goes, so that its more legible. For color, no need */
3542 do_relieve_rectangle(
3543 dpy, dest_pix, 0, 0,
3544 SWAP_ARGS(has_vt, td->offset - 3,
3545 fw->title_thickness - 1),
3546 tdd->rgc, tdd->sgc, td->cd->relief_width, False);
3547 do_relieve_rectangle(
3548 dpy, dest_pix,
3549 SWAP_ARGS(has_vt, td->offset + td->length + 2, 0),
3550 SWAP_ARGS(has_vt, fw->title_length - td->length -
3551 td->offset - 3, fw->title_thickness - 1),
3552 tdd->rgc, tdd->sgc, td->cd->relief_width, False);
3553 XDrawLine(
3554 dpy, dest_pix, tdd->sgc,
3555 SWAP_ARGS(has_vt, 0, td->offset + td->length + 1),
3556 SWAP_ARGS(has_vt, td->offset + td->length + 1,
3557 fw->title_thickness));
3559 return;
3562 static void border_draw_title_relief(
3563 FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3564 Pixmap dest_pix)
3566 int reverse = 0;
3567 rotation_t rotation;
3569 if (td->td_is_rotated)
3571 rotation = td->restore_rotation;
3573 else
3575 rotation = ROTATION_0;
3577 /* draw title relief */
3578 switch (DFS_BUTTON_RELIEF(*tdd->tstyle))
3580 case DFS_BUTTON_IS_SUNK:
3581 reverse = 1;
3582 case DFS_BUTTON_IS_UP:
3583 do_relieve_rectangle_with_rotation(
3584 dpy, dest_pix, 0, 0,
3585 SWAP_ARGS(
3586 td->has_vt, fw->title_length - 1,
3587 fw->title_thickness - 1),
3588 (reverse) ? tdd->sgc : tdd->rgc,
3589 (reverse) ? tdd->rgc : tdd->sgc, td->cd->relief_width,
3590 True, rotation);
3591 break;
3592 default:
3593 /* flat */
3594 break;
3597 return;
3600 static void border_draw_title_deep(
3601 FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3602 FlocaleWinString *fstr, Pixmap dest_pix, Window w)
3604 DecorFace *df;
3605 pixmap_background_type bg;
3607 bg.flags.use_pixmap = 0;
3608 for (df = tdd->df; df != NULL; df = df->next)
3610 if (df->style.face_type == MultiPixmap)
3612 border_mp_draw_mp_titlebar(
3613 fw, td, df, dest_pix, w);
3615 else
3617 bg.pixel = df->u.back;
3618 border_draw_decor_to_pixmap(
3619 fw, dest_pix, w, &bg, &td->layout.title_g, df,
3620 td, td->tbstate.tstate, True, tdd->is_toggled,
3624 FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0);
3626 return;
3629 static void border_get_titlebar_draw_descr(
3630 FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd,
3631 Pixmap dest_pix)
3633 rectangle *title_g;
3635 memset(tdd, 0, sizeof(*tdd));
3636 /* prepare the gcs and variables */
3637 if (td->tbstate.is_title_pressed)
3639 tdd->rgc = td->cd->shadow_gc;
3640 tdd->sgc = td->cd->relief_gc;
3642 else
3644 tdd->rgc = td->cd->relief_gc;
3645 tdd->sgc = td->cd->shadow_gc;
3647 NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color);
3648 title_g = &td->layout.title_g;
3649 tdd->tstyle = &TB_STATE(
3650 GetDecor(fw, titlebar))[td->tbstate.tstate].style;
3651 tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate];
3653 /* fetch the title string */
3654 tdd->fstr.str = fw->visible_name;
3655 tdd->fstr.win = dest_pix;
3656 if (td->td_is_rotated)
3658 tdd->fstr.flags.text_rotation = ROTATION_0;
3660 else
3662 tdd->fstr.flags.text_rotation = fw->title_text_rotation;
3664 if (td->has_vt)
3666 tdd->fstr.y = td->offset;
3667 tdd->fstr.x = fw->title_text_offset + 1;
3669 else
3671 tdd->fstr.x = td->offset;
3672 tdd->fstr.y = fw->title_text_offset + 1;
3674 if (td->cd->cs >= 0)
3676 tdd->fstr.colorset = &Colorset[td->cd->cs];
3677 tdd->fstr.flags.has_colorset = 1;
3679 tdd->fstr.gc = Scr.TitleGC;
3681 return;
3684 static void border_set_title_pixmap(
3685 FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w)
3687 pixmap_background_type bg;
3688 title_draw_descr tdd;
3689 FlocaleWinString fstr;
3690 Bool free_bg_pixmap = False;
3691 rectangle pix_g;
3693 border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix);
3694 /* prepare background, either from the window colour or from the
3695 * border style */
3696 if (!DFS_USE_BORDER_STYLE(*tdd.tstyle))
3698 /* fill with the button background colour */
3699 bg.flags.use_pixmap = 0;
3700 bg.pixel = td->cd->back_color;
3701 pix_g.x = 0;
3702 pix_g.y = 0;
3703 pix_g.width = td->layout.title_g.width;
3704 pix_g.height = td->layout.title_g.height;
3705 border_fill_pixmap_background(
3706 *dest_pix, &pix_g, &bg, td->cd);
3708 else
3710 /* draw pixmap background inherited from border style */
3711 rectangle relative_g;
3712 Pixmap tmp;
3714 if (td->draw_rotation != ROTATION_0)
3716 tmp = CreateRotatedPixmap(
3717 dpy, *dest_pix,
3718 td->layout.title_g.width,
3719 td->layout.title_g.height,
3720 Pdepth, Scr.BordersGC, td->restore_rotation);
3721 XFreePixmap(dpy, *dest_pix);
3722 *dest_pix = tmp;
3723 border_rotate_titlebar_descr(fw, td);
3725 relative_g.width = td->frame_g.width;
3726 relative_g.height = td->frame_g.height;
3727 relative_g.x = td->layout.title_g.x;
3728 relative_g.y = td->layout.title_g.y;
3729 border_get_border_background(
3730 &bg, td->cd, &td->layout.title_g, &relative_g,
3731 &free_bg_pixmap, w);
3732 bg.pixmap.g.x = 0;
3733 bg.pixmap.g.y = 0;
3734 /* set the geometry for drawing the Tiled pixmap;
3735 * FIXME: maybe add the relief as offset? */
3736 pix_g.x = 0;
3737 pix_g.y = 0;
3738 pix_g.width = td->layout.title_g.width;
3739 pix_g.height = td->layout.title_g.height;
3740 border_fill_pixmap_background(
3741 *dest_pix, &pix_g, &bg, td->cd);
3742 if (free_bg_pixmap && bg.pixmap.p)
3744 XFreePixmap(dpy, bg.pixmap.p);
3746 if (td->draw_rotation != ROTATION_0)
3748 tmp = CreateRotatedPixmap(
3749 dpy, *dest_pix,
3750 td->layout.title_g.width,
3751 td->layout.title_g.height,
3752 Pdepth, Scr.BordersGC, td->draw_rotation);
3753 XFreePixmap(dpy, *dest_pix);
3754 *dest_pix = tmp;
3755 border_rotate_titlebar_descr(fw, td);
3759 if (Pdepth < 2)
3761 border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix);
3763 else
3765 border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w);
3767 border_draw_title_relief(fw, td, &tdd, *dest_pix);
3768 border_draw_title_stick_lines(fw, td, &tdd, *dest_pix);
3770 return;
3773 static void border_draw_title(
3774 FvwmWindow *fw, titlebar_descr *td)
3776 Pixmap p;
3778 if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0)
3780 return;
3782 if (td->draw_rotation != ROTATION_0)
3784 border_rotate_titlebar_descr(fw, td);
3786 /* make a pixmap */
3787 p = border_create_decor_pixmap(td->cd, &(td->layout.title_g));
3788 /* set the background tile */
3789 #if 0
3790 fprintf(stderr,"drawing title\n");
3791 #endif
3792 border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw));
3793 if (td->draw_rotation != ROTATION_0)
3795 Pixmap tmp;
3797 tmp = CreateRotatedPixmap(
3798 dpy, p, td->layout.title_g.width,
3799 td->layout.title_g.height, Pdepth, Scr.BordersGC,
3800 td->draw_rotation);
3801 XFreePixmap(dpy, p);
3802 p = tmp;
3803 border_rotate_titlebar_descr(fw, td);
3805 /* apply the pixmap and destroy it */
3806 border_set_part_background(FW_W_TITLE(fw), p);
3807 XFreePixmap(dpy, p);
3808 if (td->tbstate.do_clear_title)
3810 XClearWindow(dpy, FW_W_TITLE(fw));
3813 return;
3816 static void border_draw_buttons(
3817 FvwmWindow *fw, titlebar_descr *td)
3819 int i;
3821 /* draw everything in a big loop */
3822 #if 0
3823 fprintf(stderr, "drawing buttons 0x%04x\n", td->tbstate.draw_bmask);
3824 #endif
3825 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
3827 unsigned int mask = (1 << i);
3829 if ((td->tbstate.draw_bmask & mask) != 0)
3831 border_draw_one_button(fw, td, i);
3834 /* update the button states */
3835 fw->decor_state.buttons_drawn |= td->tbstate.draw_bmask;
3836 fw->decor_state.buttons_inverted = td->tbstate.pressed_bmask;
3837 fw->decor_state.buttons_lit = td->tbstate.lit_bmask;
3838 fw->decor_state.buttons_toggled = td->tbstate.toggled_bmask;
3840 return;
3843 static void border_setup_use_title_style(
3844 FvwmWindow *fw, titlebar_descr *td)
3846 int i;
3847 DecorFace *df, *tsdf;
3848 ButtonState bs, tsbs;
3850 /* use a full bar pixmap (for Colorset) or non window size pixmaps
3851 * (for MultiPixmap) under certain condition:
3852 * - for the buttons which use title style
3853 * - for title which have a button with UseTitle style
3855 tsbs = td->tbstate.tstate;
3856 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
3858 bs = td->tbstate.bstate[i];
3859 df = &TB_STATE(GetDecor(fw, buttons[i]))[bs];
3860 tsdf = &TB_STATE(GetDecor(fw, buttons[i]))[tsbs];
3861 if (FW_W_BUTTON(fw, i) != None)
3863 if (DFS_USE_TITLE_STYLE(df->style))
3865 border_setup_bar_pixmaps(
3866 td, &(td->cd->dynamic_cd),
3867 &TB_STATE(GetDecor(fw, titlebar))[bs],
3868 bs);
3870 if (DFS_USE_TITLE_STYLE(tsdf->style))
3872 border_setup_bar_pixmaps(
3873 td, &(td->cd->dynamic_cd),
3874 &TB_STATE(GetDecor(fw, titlebar))[tsbs],
3875 tsbs);
3879 return;
3882 static void border_rotate_titlebar_descr(
3883 FvwmWindow *fw, titlebar_descr *td)
3885 rotation_t rotation;
3886 int i, tmpi;
3887 static titlebar_descr saved_td;
3889 if (td->draw_rotation == ROTATION_0)
3891 return;
3893 if (!td->has_been_saved)
3895 td->has_been_saved = True;
3896 memcpy(&saved_td, td, sizeof(titlebar_descr));
3898 if (!td->td_is_rotated)
3900 /* make the bar horizontal */
3901 switch(td->draw_rotation)
3903 case ROTATION_90: /* cw */
3904 rotation = ROTATION_270;
3905 break;
3906 case ROTATION_270: /* ccw */
3907 rotation = ROTATION_90;
3908 break;
3909 case ROTATION_180:
3910 rotation = ROTATION_180;
3911 break;
3912 default:
3913 return;
3915 td->has_vt = 0;
3916 td->has_an_upsidedown_rotation = 0;
3917 td->td_is_rotated = 1;
3919 else
3921 /* restore */
3922 memcpy(td, &saved_td, sizeof(titlebar_descr));
3923 td->td_is_rotated = 0;
3924 return;
3927 #define ROTATE_RECTANGLE(rot, r, vs_frame, vs_titlebar, vs_title) \
3929 rectangle tr; \
3930 tr.x = r->x; \
3931 tr.y = r->y; \
3932 tr.width = r->width; \
3933 tr.height = r->height; \
3934 switch(rot) \
3936 case ROTATION_270: /* ccw */ \
3937 tr.x = r->y; \
3938 if (vs_frame) \
3940 tr.y = td->frame_g.width - (r->x+r->width); \
3942 else if (vs_titlebar) \
3944 tr.y = td->bar_g.width - \
3945 (r->x+r->width); \
3947 else if (vs_title) \
3949 tr.y = td->layout.title_g.width - \
3950 (r->x+r->width); \
3952 else \
3954 tr.y = r->x; \
3956 tr.width = r->height; \
3957 tr.height = r->width; \
3958 break; \
3959 case ROTATION_90: /* cw */ \
3960 if (vs_frame) \
3962 tr.x = td->frame_g.height - (r->y+r->height); \
3964 else if (vs_titlebar) \
3966 tr.x = td->bar_g.height - \
3967 (r->y+r->height); \
3969 else if (vs_title) \
3971 tr.x = td->layout.title_g.height - \
3972 (r->y+r->height); \
3974 else \
3976 tr.x = r->y; \
3978 tr.y = r->x; \
3979 tr.width = r->height; \
3980 tr.height = r->width; \
3981 break; \
3982 case ROTATION_180: \
3983 if (vs_frame) \
3985 tr.x = td->frame_g.width - (r->x+r->width); \
3987 else if (vs_titlebar) \
3989 tr.x = td->bar_g.width - \
3990 (r->x + r->width); \
3992 else if (vs_title) \
3994 tr.x = td->layout.title_g.width - \
3995 (r->x + r->width); \
3997 else \
3999 tr.x = r->x; \
4001 break; \
4002 case ROTATION_0: \
4003 break; \
4005 r->x = tr.x; \
4006 r->y = tr.y; \
4007 r->width = tr.width; \
4008 r->height = tr.height; \
4011 switch(rotation)
4013 case ROTATION_90:
4014 td->offset =
4015 td->layout.title_g.height - td->offset - td->length;
4016 tmpi = td->left_end_length;
4017 td->left_end_length = td->right_end_length;
4018 td->right_end_length = tmpi;
4019 tmpi = td->left_of_text_length;
4020 td->left_of_text_length = td->right_of_text_length;
4021 td->right_of_text_length = tmpi;
4022 break;
4023 case ROTATION_270:
4024 break;
4025 case ROTATION_180:
4026 td->offset = td->layout.title_g.width - td->offset - td->length;
4027 tmpi = td->left_end_length;
4028 td->left_end_length = td->right_end_length;
4029 td->right_end_length = tmpi;
4030 tmpi = td->left_of_text_length;
4031 td->left_of_text_length = td->right_of_text_length;
4032 td->right_of_text_length = tmpi;
4033 break;
4034 case ROTATION_0:
4035 break;
4038 ROTATE_RECTANGLE(rotation, (&td->left_buttons_g), True, False, False)
4039 ROTATE_RECTANGLE(rotation, (&td->right_buttons_g), True, False, False)
4040 for (i=0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4042 ROTATE_RECTANGLE(
4043 rotation, (&td->layout.button_g[i]), True, False, False)
4045 ROTATE_RECTANGLE(rotation, (&td->under_text_g), False, False, True)
4046 ROTATE_RECTANGLE(rotation, (&td->left_main_g), False, False, True)
4047 ROTATE_RECTANGLE(rotation, (&td->right_main_g), False, False, True)
4048 ROTATE_RECTANGLE(rotation, (&td->full_left_main_g), True, False, False)
4049 ROTATE_RECTANGLE(rotation, (&td->full_right_main_g), True, False, False)
4050 ROTATE_RECTANGLE(rotation, (&td->layout.title_g), True, False, False)
4051 ROTATE_RECTANGLE(rotation, (&td->bar_g), True, False, False)
4052 ROTATE_RECTANGLE(rotation, (&td->frame_g), False, False, False);
4054 #undef ROTATE_RECTANGLE
4057 static void border_get_titlebar_descr_state(
4058 FvwmWindow *fw, window_parts pressed_parts, int pressed_button,
4059 clear_window_parts clear_parts, Bool do_hilight,
4060 border_titlebar_state *tbstate)
4062 int i;
4064 if ((pressed_parts & PART_BUTTONS) != PART_NONE && pressed_button >= 0)
4066 tbstate->pressed_bmask = (1 << pressed_button);
4068 else
4070 tbstate->pressed_bmask = 0;
4072 if ((clear_parts & CLEAR_BUTTONS) != CLEAR_NONE)
4074 tbstate->clear_bmask = ~0;
4076 else
4078 tbstate->clear_bmask = 0;
4080 tbstate->lit_bmask = (do_hilight == True) ? ~0 : 0;
4081 if ((pressed_parts & PART_TITLE) != PART_NONE)
4083 tbstate->is_title_pressed = 1;
4085 else
4087 tbstate->is_title_pressed = 0;
4089 if ((clear_parts & CLEAR_TITLE) != CLEAR_NONE)
4091 tbstate->do_clear_title = 1;
4093 else
4095 tbstate->do_clear_title = 0;
4097 tbstate->is_title_lit = (do_hilight == True) ? 1 : 0;
4098 tbstate->toggled_bmask = 0;
4099 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4101 unsigned int mask = (1 << i);
4103 if (is_button_toggled(fw, i))
4105 tbstate->toggled_bmask |= mask;
4107 tbstate->bstate[i] = border_flags_to_button_state(
4108 tbstate->pressed_bmask & mask,
4109 tbstate->lit_bmask & mask,
4110 tbstate->toggled_bmask & mask);
4112 tbstate->tstate = border_flags_to_button_state(
4113 tbstate->is_title_pressed, tbstate->is_title_lit, 0);
4116 static window_parts border_get_titlebar_descr(
4117 common_decorations_type *cd, FvwmWindow *fw,
4118 window_parts pressed_parts, int pressed_button,
4119 window_parts force_draw_parts, clear_window_parts clear_parts,
4120 rectangle *old_g, rectangle *new_g, Bool do_hilight,
4121 titlebar_descr *ret_td)
4123 window_parts draw_parts;
4124 int i;
4125 DecorFace *df;
4126 int is_start = 0;
4127 JustificationType just;
4128 int lbl = 0;
4129 int rbl = 0;
4131 ret_td->cd = cd;
4132 ret_td->frame_g = *new_g;
4133 if (old_g == NULL)
4135 old_g = &fw->g.frame;
4137 frame_get_titlebar_dimensions(fw, old_g, NULL, &ret_td->old_layout);
4138 frame_get_titlebar_dimensions(fw, new_g, NULL, &ret_td->layout);
4140 ret_td->has_vt = HAS_VERTICAL_TITLE(fw);
4141 if (USE_TITLE_DECOR_ROTATION(fw))
4143 ret_td->draw_rotation = fw->title_text_rotation;
4144 switch(ret_td->draw_rotation)
4146 case ROTATION_90:
4147 ret_td->restore_rotation = ROTATION_270;
4148 break;
4149 case ROTATION_270: /* ccw */
4150 ret_td->restore_rotation = ROTATION_90;
4151 break;
4152 case ROTATION_180:
4153 ret_td->restore_rotation = ROTATION_180;
4154 break;
4155 default:
4156 break;
4159 if (fw->title_text_rotation == ROTATION_270 ||
4160 fw->title_text_rotation == ROTATION_180)
4162 ret_td->has_an_upsidedown_rotation = True;
4164 /* geometry of the title bar title + buttons */
4165 if (!ret_td->has_vt)
4167 ret_td->bar_g.width = new_g->width - 2 * fw->boundary_width;
4168 ret_td->bar_g.height = ret_td->layout.title_g.height;
4169 ret_td->bar_g.x = fw->boundary_width;
4170 ret_td->bar_g.y = ret_td->layout.title_g.y;
4172 else
4174 ret_td->bar_g.width = ret_td->layout.title_g.width;
4175 ret_td->bar_g.height = new_g->height - 2 * fw->boundary_width;
4176 ret_td->bar_g.y = fw->boundary_width;
4177 ret_td->bar_g.x = ret_td->layout.title_g.x;
4180 /* buttons geometries */
4181 if (ret_td->has_vt)
4183 ret_td->left_buttons_g.width = ret_td->bar_g.width;
4184 ret_td->right_buttons_g.width = ret_td->bar_g.width;
4186 else
4188 ret_td->left_buttons_g.height = ret_td->bar_g.height;
4189 ret_td->right_buttons_g.height = ret_td->bar_g.width;
4192 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4194 if (FW_W_BUTTON(fw, i) == None)
4196 continue;
4198 if (ret_td->has_vt)
4200 if (i & 1)
4202 rbl += ret_td->layout.button_g[i].height;
4204 else
4206 lbl += ret_td->layout.button_g[i].height;
4209 else
4211 if (i & 1)
4213 rbl += ret_td->layout.button_g[i].width;
4215 else
4217 lbl += ret_td->layout.button_g[i].width;
4222 if (ret_td->has_an_upsidedown_rotation)
4224 if (ret_td->has_vt)
4226 ret_td->left_buttons_g.height = rbl;
4227 ret_td->right_buttons_g.height = lbl;
4228 ret_td->right_buttons_g.y = fw->boundary_width;
4229 ret_td->right_buttons_g.x = ret_td->bar_g.x;
4230 ret_td->left_buttons_g.y = ret_td->layout.title_g.y +
4231 ret_td->layout.title_g.height;
4232 ret_td->left_buttons_g.x = ret_td->bar_g.x;
4234 else
4236 ret_td->left_buttons_g.width = rbl;
4237 ret_td->right_buttons_g.width = lbl;
4238 ret_td->right_buttons_g.x = fw->boundary_width;
4239 ret_td->right_buttons_g.y = ret_td->bar_g.y;
4240 ret_td->left_buttons_g.x = ret_td->layout.title_g.x +
4241 ret_td->layout.title_g.width;
4242 ret_td->left_buttons_g.y = ret_td->bar_g.y;
4245 else
4247 if (ret_td->has_vt)
4249 ret_td->left_buttons_g.height = lbl;
4250 ret_td->right_buttons_g.height = rbl;
4251 ret_td->left_buttons_g.y = fw->boundary_width;
4252 ret_td->left_buttons_g.x = ret_td->bar_g.x;
4253 ret_td->right_buttons_g.y = ret_td->layout.title_g.y +
4254 ret_td->layout.title_g.height;
4255 ret_td->right_buttons_g.x = ret_td->bar_g.x;
4257 else
4259 ret_td->left_buttons_g.width = lbl;
4260 ret_td->right_buttons_g.width = rbl;
4261 ret_td->left_buttons_g.x = fw->boundary_width;
4262 ret_td->left_buttons_g.y = ret_td->bar_g.y;
4263 ret_td->right_buttons_g.x = ret_td->layout.title_g.x +
4264 ret_td->layout.title_g.width;
4265 ret_td->right_buttons_g.y = ret_td->bar_g.y;
4269 /* initialise flags */
4270 border_get_titlebar_descr_state(
4271 fw, pressed_parts, pressed_button, clear_parts, do_hilight,
4272 &(ret_td->tbstate));
4274 /* get the title string length and position
4275 * This is not in "tdd" (titlebar_draw_descr), because these are needed
4276 * to draw the buttons with UseTitleStyle */
4277 just = TB_JUSTIFICATION(GetDecor(fw, titlebar));
4278 if (fw->visible_name != (char *)NULL)
4280 ret_td->length = FlocaleTextWidth(
4281 fw->title_font, fw->visible_name,
4282 (ret_td->has_vt) ? -strlen(fw->visible_name) :
4283 strlen(fw->visible_name));
4284 if (ret_td->length > fw->title_length -
4285 2*MIN_WINDOW_TITLE_TEXT_OFFSET)
4287 ret_td->length = fw->title_length -
4288 2*MIN_WINDOW_TITLE_TEXT_OFFSET;
4289 just = JUST_CENTER;
4291 if (ret_td->length < 0)
4293 ret_td->length = 0;
4296 else
4298 ret_td->length = 0;
4300 if (ret_td->length == 0)
4302 just = JUST_CENTER;
4304 df = &TB_STATE(GetDecor(fw, titlebar))[ret_td->tbstate.tstate];
4305 switch (just)
4307 case JUST_LEFT:
4308 is_start = 1;
4309 /* fall through */
4310 case JUST_RIGHT:
4311 if (ret_td->has_an_upsidedown_rotation)
4313 is_start = !is_start;
4315 if (is_start)
4317 if (WINDOW_TITLE_TEXT_OFFSET + ret_td->length <=
4318 fw->title_length)
4320 ret_td->offset = WINDOW_TITLE_TEXT_OFFSET;
4322 else
4324 ret_td->offset =
4325 fw->title_length - ret_td->length;
4328 else
4330 ret_td->offset = fw->title_length - ret_td->length -
4331 WINDOW_TITLE_TEXT_OFFSET;
4333 break;
4334 case JUST_CENTER:
4335 default:
4336 ret_td->offset = (fw->title_length - ret_td->length) / 2;
4337 break;
4340 if (ret_td->offset < MIN_WINDOW_TITLE_TEXT_OFFSET)
4342 ret_td->offset = MIN_WINDOW_TITLE_TEXT_OFFSET;
4345 /* setup MultiPixmap */
4346 border_mp_get_titlebar_descr(fw, ret_td, df);
4348 /* determine the parts to draw */
4349 draw_parts = border_get_tb_parts_to_draw(
4350 fw, ret_td, old_g, new_g, force_draw_parts);
4352 return draw_parts;
4356 static void border_draw_titlebar(
4357 common_decorations_type *cd, FvwmWindow *fw,
4358 window_parts pressed_parts, int pressed_button,
4359 window_parts force_draw_parts, clear_window_parts clear_parts,
4360 rectangle *old_g, rectangle *new_g, Bool do_hilight)
4362 window_parts draw_parts;
4363 titlebar_descr td;
4365 if (!HAS_TITLE(fw))
4367 /* just reset border states */
4368 fw->decor_state.parts_drawn &= ~(PART_TITLE);
4369 fw->decor_state.parts_lit &= ~(PART_TITLE);
4370 fw->decor_state.parts_inverted &= ~(PART_TITLE);
4371 fw->decor_state.buttons_drawn = 0;
4372 fw->decor_state.buttons_lit = 0;
4373 fw->decor_state.buttons_inverted = 0;
4374 fw->decor_state.buttons_toggled = 0;
4375 return;
4377 memset(&td, 0, sizeof(td));
4378 draw_parts = border_get_titlebar_descr(
4379 cd, fw, pressed_parts, pressed_button, force_draw_parts,
4380 clear_parts, old_g, new_g, do_hilight, &td);
4381 if ((draw_parts & PART_TITLE) != PART_NONE ||
4382 (draw_parts & PART_BUTTONS) != PART_NONE)
4384 /* set up UseTitleStyle Colorset */
4385 border_setup_use_title_style(fw, &td);
4387 if ((draw_parts & PART_TITLE) != PART_NONE)
4389 border_draw_title(fw, &td);
4391 if ((draw_parts & PART_BUTTONS) != PART_NONE)
4393 border_draw_buttons(fw, &td);
4395 border_free_bar_pixmaps(&(td.cd->dynamic_cd));
4397 /* update the decor states */
4398 fw->decor_state.parts_drawn |= draw_parts;
4399 if (do_hilight)
4401 fw->decor_state.parts_lit |= draw_parts;
4403 else
4405 fw->decor_state.parts_lit &= ~draw_parts;
4407 fw->decor_state.parts_inverted &= ~draw_parts;
4408 fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
4409 if (draw_parts & PART_BUTTONS)
4411 fw->decor_state.buttons_drawn |= td.tbstate.draw_bmask;
4412 fw->decor_state.parts_lit = (do_hilight) ? ~0 : 0;
4413 if (td.tbstate.pressed_bmask)
4415 fw->decor_state.buttons_inverted =
4416 td.tbstate.pressed_bmask;
4418 else
4420 fw->decor_state.buttons_inverted &=
4421 ~td.tbstate.draw_bmask;
4423 fw->decor_state.buttons_toggled =
4424 (fw->decor_state.buttons_toggled &
4425 ~td.tbstate.max_bmask) | td.tbstate.toggled_bmask;
4428 return;
4433 * Redraws the windows borders
4436 static void border_draw_border_parts(
4437 common_decorations_type *cd, FvwmWindow *fw,
4438 window_parts pressed_parts, window_parts force_draw_parts,
4439 clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g,
4440 Bool do_hilight)
4442 border_relief_descr br;
4443 window_parts draw_parts;
4444 Bool do_clear;
4446 if (HAS_NO_BORDER(fw))
4448 /* just reset border states */
4449 fw->decor_state.parts_drawn &= ~(PART_FRAME | PART_HANDLES);
4450 fw->decor_state.parts_lit &= ~(PART_FRAME | PART_HANDLES);
4451 fw->decor_state.parts_inverted &= ~(PART_FRAME | PART_HANDLES);
4452 return;
4454 do_clear = (clear_parts & CLEAR_FRAME) ? True : False;
4455 /* determine the parts to draw and the position to place them */
4456 if (HAS_DEPRESSABLE_BORDER(fw))
4458 pressed_parts &= PART_FRAME;
4460 else
4462 pressed_parts = PART_NONE;
4464 force_draw_parts &= PART_FRAME;
4465 memset(&br, 0, sizeof(br));
4466 draw_parts = border_get_parts_and_pos_to_draw(
4467 cd, fw, pressed_parts, force_draw_parts, old_g, new_g,
4468 do_hilight, &br);
4469 if ((draw_parts & PART_FRAME) != PART_NONE)
4471 border_draw_all_border_parts(
4472 cd, fw, &br, new_g, draw_parts, pressed_parts,
4473 do_hilight, do_clear);
4475 /* update the decor states */
4476 fw->decor_state.parts_drawn |= draw_parts;
4477 if (do_hilight)
4479 fw->decor_state.parts_lit |= draw_parts;
4481 else
4483 fw->decor_state.parts_lit &= ~draw_parts;
4485 fw->decor_state.parts_inverted &= ~draw_parts;
4486 fw->decor_state.parts_inverted |= (draw_parts & pressed_parts);
4488 return;
4491 /* ---------------------------- interface functions ------------------------ */
4493 DecorFace *border_get_border_style(
4494 FvwmWindow *fw, Bool has_focus)
4496 DecorFace *df;
4498 if (has_focus == True)
4500 df = &(GetDecor(fw, BorderStyle.active));
4502 else
4504 df = &(GetDecor(fw, BorderStyle.inactive));
4507 return df;
4510 int border_is_using_border_style(
4511 FvwmWindow *fw, Bool has_focus)
4513 ButtonState bs;
4514 int is_pressed;
4515 int is_toggled;
4516 int i;
4518 /* title */
4519 is_pressed = (FW_W_TITLE(fw) == PressedW);
4520 bs = border_flags_to_button_state(is_pressed, has_focus, 0);
4521 if (DFS_USE_BORDER_STYLE(TB_STATE(GetDecor(fw, titlebar))[bs].style))
4523 return 1;
4525 for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4527 if (FW_W_BUTTON(fw, i) == None)
4529 continue;
4531 is_pressed = (FW_W_BUTTON(fw, i) == PressedW);
4532 is_toggled = (is_button_toggled(fw, i) == True);
4533 bs = border_flags_to_button_state(
4534 is_pressed, (has_focus == True), is_toggled);
4535 if (DFS_USE_BORDER_STYLE(
4536 TB_STATE(GetDecor(fw, buttons[i]))[bs].style))
4538 return 1;
4542 return 0;
4545 int border_context_to_parts(
4546 int context)
4548 if (context == C_FRAME || context == C_SIDEBAR ||
4549 context == (C_FRAME | C_SIDEBAR))
4551 return PART_FRAME;
4553 else if (context == C_F_TOPLEFT)
4555 return PART_BORDER_NW;
4557 else if (context == C_F_TOPRIGHT)
4559 return PART_BORDER_NE;
4561 else if (context == C_F_BOTTOMLEFT)
4563 return PART_BORDER_SW;
4565 else if (context == C_F_BOTTOMRIGHT)
4567 return PART_BORDER_SE;
4569 else if (context == C_SB_LEFT)
4571 return PART_BORDER_W;
4573 else if (context == C_SB_RIGHT)
4575 return PART_BORDER_E;
4577 else if (context == C_SB_TOP)
4579 return PART_BORDER_N;
4581 else if (context == C_SB_BOTTOM)
4583 return PART_BORDER_S;
4585 else if (context == C_TITLE)
4587 return PART_TITLE;
4589 else if (context & (C_LALL | C_RALL))
4591 return PART_BUTTONS;
4594 return PART_NONE;
4597 void border_get_part_geometry(
4598 FvwmWindow *fw, window_parts part, rectangle *sidebar_g,
4599 rectangle *ret_g, Window *ret_w)
4601 int bw;
4603 bw = fw->boundary_width;
4604 /* ret_g->x and ret->y is just an offset relatively to the w,
4605 * maybe we can take the relief in account? */
4606 switch (part)
4608 case PART_BORDER_N:
4609 ret_g->x = sidebar_g->x;
4610 ret_g->y = 0;
4611 *ret_w = FW_W_SIDE(fw, 0);
4612 break;
4613 case PART_BORDER_E:
4614 ret_g->x = 2 * sidebar_g->x + sidebar_g->width - bw;
4615 ret_g->y = sidebar_g->y;
4616 *ret_w = FW_W_SIDE(fw, 1);
4617 break;
4618 case PART_BORDER_S:
4619 ret_g->x = sidebar_g->x;
4620 ret_g->y = 2 * sidebar_g->y + sidebar_g->height - bw;
4621 *ret_w = FW_W_SIDE(fw, 2);
4622 break;
4623 case PART_BORDER_W:
4624 ret_g->x = 0;
4625 ret_g->y = sidebar_g->y;
4626 *ret_w = FW_W_SIDE(fw, 3);
4627 break;
4628 case PART_BORDER_NW:
4629 ret_g->x = 0;
4630 ret_g->y = 0;
4631 *ret_w = FW_W_CORNER(fw, 0);
4632 break;
4633 case PART_BORDER_NE:
4634 ret_g->x = sidebar_g->x + sidebar_g->width;
4635 ret_g->y = 0;
4636 *ret_w = FW_W_CORNER(fw, 1);
4637 break;
4638 case PART_BORDER_SW:
4639 ret_g->x = 0;
4640 ret_g->y = sidebar_g->y + sidebar_g->height;
4641 *ret_w = FW_W_CORNER(fw, 2);
4642 break;
4643 case PART_BORDER_SE:
4644 ret_g->x = sidebar_g->x + sidebar_g->width;
4645 ret_g->y = sidebar_g->y + sidebar_g->height;
4646 *ret_w = FW_W_CORNER(fw, 3);
4647 break;
4648 default:
4649 break;
4652 switch (part)
4654 case PART_BORDER_N:
4655 case PART_BORDER_S:
4656 ret_g->width = sidebar_g->width;
4657 ret_g->height = bw;
4658 break;
4659 case PART_BORDER_E:
4660 case PART_BORDER_W:
4661 ret_g->width = bw;
4662 ret_g->height = sidebar_g->height;
4663 break;
4664 case PART_BORDER_NW:
4665 case PART_BORDER_NE:
4666 case PART_BORDER_SW:
4667 case PART_BORDER_SE:
4668 ret_g->width = sidebar_g->x;
4669 ret_g->height = sidebar_g->y;
4670 break;
4671 default:
4672 return;
4675 return;
4678 int get_button_number(int context)
4680 int i;
4682 for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++)
4684 if (context & (C_L1 << i))
4686 return i;
4690 return -1;
4693 void border_draw_decorations(
4694 FvwmWindow *fw, window_parts draw_parts, Bool has_focus, Bool do_force,
4695 clear_window_parts clear_parts, rectangle *old_g, rectangle *new_g)
4697 common_decorations_type cd;
4698 Bool do_redraw_titlebar = False;
4699 window_parts pressed_parts;
4700 window_parts force_parts;
4701 int context;
4702 int item;
4704 if (fw == NULL)
4706 return;
4708 if (WAS_NEVER_DRAWN(fw))
4710 /* force drawing everything */
4711 do_force = True;
4712 draw_parts = PART_ALL;
4713 SET_WAS_NEVER_DRAWN(fw, 0);
4715 memset(&cd, 0, sizeof(cd));
4717 /* can't compare with True here, old code calls this with value "2" */
4718 if (do_force != False)
4720 force_parts = draw_parts;
4722 else
4724 force_parts = PART_NONE;
4726 if (has_focus)
4728 /* don't re-draw just for kicks */
4729 if (Scr.Hilite != fw && Scr.Hilite != NULL)
4731 FvwmWindow *t = Scr.Hilite;
4733 Scr.Hilite = NULL;
4734 /* make sure that the previously highlighted
4735 * window got unhighlighted */
4736 border_draw_decorations(
4737 t, PART_ALL, False, True, CLEAR_ALL, NULL,
4738 NULL);
4740 Scr.Hilite = fw;
4742 else if (fw == Scr.Hilite)
4744 Scr.Hilite = NULL;
4746 if (fw->Desk != Scr.CurrentDesk)
4748 return;
4750 if (IS_ICONIFIED(fw))
4752 DrawIconWindow(fw, True, True, True, False, NULL);
4753 return;
4755 /* calculate some values and flags */
4756 if ((draw_parts & PART_TITLEBAR) && HAS_TITLE(fw))
4758 do_redraw_titlebar = True;
4760 get_common_decorations(
4761 &cd, fw, draw_parts, has_focus, False, do_redraw_titlebar);
4762 /* redraw */
4763 context = frame_window_id_to_context(fw, PressedW, &item);
4764 if ((context & (C_LALL | C_RALL)) == 0)
4766 item = -1;
4768 pressed_parts = border_context_to_parts(context);
4769 if (new_g == NULL)
4771 new_g = &fw->g.frame;
4773 if (do_redraw_titlebar)
4775 border_draw_titlebar(
4776 &cd, fw, pressed_parts & PART_TITLEBAR, item,
4777 force_parts & PART_TITLEBAR,
4778 clear_parts, old_g, new_g, has_focus);
4780 if (draw_parts & PART_FRAME)
4782 Pixmap save_pix = cd.dynamic_cd.frame_pixmap;
4784 memset(&cd, 0, sizeof(cd));
4785 get_common_decorations(
4786 &cd, fw, draw_parts, has_focus, True, True);
4787 cd.dynamic_cd.frame_pixmap = save_pix;
4788 border_draw_border_parts(
4789 &cd, fw,
4790 (pressed_parts & (PART_FRAME | PART_HANDLES)),
4791 (force_parts & (PART_FRAME | PART_HANDLES)),
4792 clear_parts, old_g, new_g, has_focus);
4794 if (cd.dynamic_cd.frame_pixmap != None)
4796 XFreePixmap(dpy, cd.dynamic_cd.frame_pixmap);
4798 return;
4801 void border_undraw_decorations(
4802 FvwmWindow *fw)
4804 memset(&fw->decor_state, 0, sizeof(fw->decor_state));
4806 return;
4811 * redraw the decoration when style change
4814 void border_redraw_decorations(
4815 FvwmWindow *fw)
4817 FvwmWindow *u = Scr.Hilite;
4819 /* domivogt (6-Jun-2000): Don't check if the window is visible here.
4820 * If we do, some updates are not applied and when the window becomes
4821 * visible again, the X Server may not redraw the window. */
4822 border_draw_decorations(
4823 fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL);
4824 Scr.Hilite = u;
4826 return;
4831 * get the the root transparent parts of the decoration
4834 unsigned int border_get_transparent_decorations_part(FvwmWindow *fw)
4836 DecorFace *df,*tdf;
4837 unsigned int draw_parts = PART_NONE;
4838 int i;
4839 window_parts pressed_parts;
4840 int context;
4841 int item;
4842 border_titlebar_state tbstate;
4843 Bool title_use_borderstyle = False;
4844 Bool buttons_use_borderstyle = False;
4845 Bool buttons_use_titlestyle = False;
4847 context = frame_window_id_to_context(fw, PressedW, &item);
4848 if ((context & (C_LALL | C_RALL)) == 0)
4850 item = -1;
4852 pressed_parts = border_context_to_parts(context);
4854 memset(&tbstate, 0, sizeof(tbstate));
4855 border_get_titlebar_descr_state(
4856 fw, pressed_parts & PART_TITLEBAR, item,
4857 CLEAR_ALL, (Scr.Hilite == fw), &tbstate);
4859 for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
4861 df = &TB_STATE(GetDecor(fw, buttons[i]))[tbstate.bstate[i]];
4863 if (DFS_USE_TITLE_STYLE(df->style))
4865 buttons_use_titlestyle = True;
4867 if (DFS_USE_BORDER_STYLE(df->style))
4869 buttons_use_borderstyle = True;
4871 for(tdf = df; tdf != NULL; tdf = tdf->next)
4873 if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
4874 CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
4876 draw_parts |= PART_BUTTONS;
4877 break;
4882 df = &TB_STATE(GetDecor(fw, titlebar))[tbstate.tstate];
4883 if (DFS_USE_BORDER_STYLE(df->style))
4885 title_use_borderstyle = True;
4887 for(tdf = df; tdf != NULL; tdf = tdf->next)
4889 if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
4890 CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs))
4892 draw_parts |= PART_TITLE;
4893 break;
4895 else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
4897 int i;
4899 for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
4901 if (CSET_IS_TRANSPARENT_ROOT(
4902 tdf->u.mp.acs[i].cs))
4904 draw_parts |= PART_TITLE;
4905 break;
4911 df = border_get_border_style(fw, (Scr.Hilite == fw));
4912 if (DFS_FACE_TYPE(df->style) == ColorsetButton &&
4913 CSET_IS_TRANSPARENT_ROOT(df->u.acs.cs))
4915 draw_parts |= PART_FRAME|PART_HANDLES;
4917 if (draw_parts & PART_FRAME)
4919 if (title_use_borderstyle)
4921 draw_parts |= PART_TITLE;
4923 if (buttons_use_borderstyle)
4925 draw_parts |= PART_BUTTONS;
4928 if ((draw_parts & PART_TITLE) && buttons_use_titlestyle)
4930 draw_parts |= PART_BUTTONS;
4932 #if 0
4933 fprintf(stderr,"Transparant Part: %u\n", draw_parts);
4934 #endif
4935 return draw_parts;
4938 /* ---------------------------- builtin commands --------------------------- */
4942 * Sets the allowed button states
4945 void CMD_ButtonState(F_CMD_ARGS)
4947 char *token;
4949 while ((token = PeekToken(action, &action)))
4951 static char first = True;
4952 if (!token && first)
4954 Scr.gs.use_active_down_buttons =
4955 DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
4956 Scr.gs.use_inactive_buttons =
4957 DEFAULT_USE_INACTIVE_BUTTONS;
4958 Scr.gs.use_inactive_down_buttons =
4959 DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
4960 return;
4962 first = False;
4963 if (StrEquals("activedown", token))
4965 Scr.gs.use_active_down_buttons = ParseToggleArgument(
4966 action, &action,
4967 DEFAULT_USE_ACTIVE_DOWN_BUTTONS, True);
4969 else if (StrEquals("inactive", token))
4971 Scr.gs.use_inactive_buttons = ParseToggleArgument(
4972 action, &action,
4973 DEFAULT_USE_INACTIVE_BUTTONS, True);
4975 else if (StrEquals("inactivedown", token))
4977 Scr.gs.use_inactive_down_buttons = ParseToggleArgument(
4978 action, &action,
4979 DEFAULT_USE_INACTIVE_DOWN_BUTTONS, True);
4981 else
4983 Scr.gs.use_active_down_buttons =
4984 DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
4985 Scr.gs.use_inactive_buttons =
4986 DEFAULT_USE_INACTIVE_BUTTONS;
4987 Scr.gs.use_inactive_down_buttons =
4988 DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
4989 fvwm_msg(ERR, "cmd_button_state",
4990 "Unknown button state %s", token);
4991 return;
4995 return;
5000 * Sets the border style (veliaa@rpi.edu)
5003 void CMD_BorderStyle(F_CMD_ARGS)
5005 char *parm;
5006 char *prev;
5007 #ifdef USEDECOR
5008 FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
5009 #else
5010 FvwmDecor *decor = &Scr.DefaultDecor;
5011 #endif
5013 Scr.flags.do_need_window_update = 1;
5014 decor->flags.has_changed = 1;
5015 for (prev = action; (parm = PeekToken(action, &action)); prev = action)
5017 if (StrEquals(parm, "active") || StrEquals(parm, "inactive"))
5019 int len;
5020 char *end, *tmp;
5021 DecorFace tmpdf, *df;
5023 memset(&tmpdf.style, 0, sizeof(tmpdf.style));
5024 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
5025 tmpdf.next = NULL;
5026 if (FMiniIconsSupported)
5028 tmpdf.u.p = NULL;
5030 if (StrEquals(parm,"active"))
5032 df = &decor->BorderStyle.active;
5034 else
5036 df = &decor->BorderStyle.inactive;
5038 df->flags.has_changed = 1;
5039 while (isspace(*action))
5041 ++action;
5043 if (*action != '(')
5045 if (!*action)
5047 fvwm_msg(
5048 ERR, "SetBorderStyle",
5049 "error in %s border"
5050 " specification", parm);
5051 return;
5053 while (isspace(*action))
5055 ++action;
5057 if (ReadDecorFace(action, &tmpdf,-1,True))
5059 FreeDecorFace(dpy, df);
5060 *df = tmpdf;
5062 break;
5064 end = strchr(++action, ')');
5065 if (!end)
5067 fvwm_msg(
5068 ERR, "SetBorderStyle",
5069 "error in %s border specification",
5070 parm);
5071 return;
5073 len = end - action + 1;
5074 tmp = safemalloc(len);
5075 strncpy(tmp, action, len - 1);
5076 tmp[len - 1] = 0;
5077 ReadDecorFace(tmp, df,-1,True);
5078 free(tmp);
5079 action = end + 1;
5081 else if (strcmp(parm,"--")==0)
5083 if (ReadDecorFace(
5084 prev, &decor->BorderStyle.active,-1,True))
5086 ReadDecorFace(
5087 prev, &decor->BorderStyle.inactive, -1,
5088 False);
5090 decor->BorderStyle.active.flags.has_changed = 1;
5091 decor->BorderStyle.inactive.flags.has_changed = 1;
5092 break;
5094 else
5096 DecorFace tmpdf;
5097 memset(&tmpdf.style, 0, sizeof(tmpdf.style));
5098 DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
5099 tmpdf.next = NULL;
5100 if (FMiniIconsSupported)
5102 tmpdf.u.p = NULL;
5104 if (ReadDecorFace(prev, &tmpdf,-1,True))
5106 FreeDecorFace(dpy,&decor->BorderStyle.active);
5107 decor->BorderStyle.active = tmpdf;
5108 ReadDecorFace(
5109 prev, &decor->BorderStyle.inactive, -1,
5110 False);
5111 decor->BorderStyle.active.flags.has_changed = 1;
5112 decor->BorderStyle.inactive.flags.has_changed =
5115 break;
5119 return;