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