/* -*-c-*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This module is all original code * by Rob Nation * Copyright 1993, Robert Nation * You may use this code for any purpose, as long as the original * copyright remains in the source code and all documentation */ /* IMPORTANT NOTE: * * The functions in this module *must not* assume that the geometries in the * FvwmWindow structure reflect the desired geometry of the window or its * parts. While the window is resized or shaded, they may hold the old * geometry instead of the new one (but you can not rely on this). Therefore, * these geometries must not be accessed directly or indirectly (by the * functions from geometry,c). Use the geometries that are passed in via * structure pointers, e.d. "td". */ /* ---------------------------- included header files ---------------------- */ #include "config.h" #include #include "libs/fvwmlib.h" #include "libs/Parse.h" #include "libs/Graphics.h" #include "libs/Picture.h" #include "libs/PictureGraphics.h" #include "libs/FRenderInit.h" #include "libs/charmap.h" #include "libs/wcontext.h" #include "fvwm.h" #include "execcontext.h" #include "externs.h" #include "misc.h" #include "screen.h" #include "geometry.h" #include "borders.h" #include "builtins.h" #include "icons.h" #include "frame.h" /* ---------------------------- local definitions -------------------------- */ /* ---------------------------- local macros ------------------------------- */ #define SWAP_ARGS(f,a1,a2) (f)?(a2):(a1),(f)?(a1):(a2) /* ---------------------------- imports ------------------------------------ */ extern Window PressedW; /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ typedef struct { struct { unsigned use_pixmap : 1; } flags; Pixel pixel; struct { Pixmap p; Pixmap shape; Pixmap alpha; int depth; FvwmRenderAttributes fra; rectangle g; int stretch_w; int stretch_h; struct { unsigned is_tiled : 1; unsigned is_stretched : 1; } flags; } pixmap; } pixmap_background_type; typedef struct { Pixmap p; FvwmPicture *mp_created_pic; int cs; FvwmPicture *mp_pic; int mp_part; Bool created; } bar_pixmap; typedef struct { int count; bar_pixmap *bps; } bar_bs_pixmaps; /* for UseTitleStyle & Colorset */ typedef struct { Pixmap frame_pixmap; bar_bs_pixmaps bar_pixmaps[BS_MaxButtonState]; } dynamic_common_decorations; typedef struct { int relief_width; GC relief_gc; GC shadow_gc; Pixel fore_color; Pixel back_color; int cs; int border_cs; /* for UseBorderStyle */ int bg_border_cs; /* for UseBorderStyle */ Pixmap back_pixmap; XSetWindowAttributes attributes; unsigned long valuemask; Pixmap texture_pixmap; int texture_pixmap_width; int texture_pixmap_height; XSetWindowAttributes notex_attributes; unsigned long notex_valuemask; dynamic_common_decorations dynamic_cd; } common_decorations_type; typedef struct { GC relief; GC shadow; GC transparent; } draw_border_gcs; typedef struct { int offset_tl; int offset_br; int thickness; int length; unsigned has_x_marks : 1; unsigned has_y_marks : 1; } border_marks_descr; typedef struct { int w_dout; int w_hiout; int w_trout; int w_c; int w_trin; int w_shin; int w_din; int sum; int trim; unsigned is_flat : 1; } border_relief_size_descr; typedef struct { rectangle sidebar_g; border_relief_size_descr relief; border_marks_descr marks; draw_border_gcs gcs; } border_relief_descr; typedef struct { unsigned pressed_bmask : NUMBER_OF_TITLE_BUTTONS; unsigned lit_bmask : NUMBER_OF_TITLE_BUTTONS; unsigned toggled_bmask : NUMBER_OF_TITLE_BUTTONS; unsigned clear_bmask : NUMBER_OF_TITLE_BUTTONS; unsigned draw_bmask : NUMBER_OF_TITLE_BUTTONS; unsigned max_bmask : NUMBER_OF_TITLE_BUTTONS; ButtonState bstate[NUMBER_OF_TITLE_BUTTONS]; unsigned is_title_pressed : 1; unsigned is_title_lit : 1; unsigned do_clear_title : 1; ButtonState tstate; } border_titlebar_state; typedef struct { GC rgc; GC sgc; FlocaleWinString fstr; DecorFaceStyle *tstyle; DecorFace *df; unsigned is_toggled : 1; } title_draw_descr; typedef struct { common_decorations_type *cd; rectangle frame_g; rectangle bar_g; /* titlebar geo vs the frame */ rectangle left_buttons_g; /* vs the frame */ rectangle right_buttons_g; /* vs the frame */ frame_title_layout_t layout; frame_title_layout_t old_layout; border_titlebar_state tbstate; int length; /* text */ int offset; /* text offset */ /* MultiPixmap Geometries */ rectangle under_text_g; /* vs the titlebar */ rectangle left_main_g; /* vs the titlebar */ rectangle right_main_g; /* vs the titlebar */ rectangle full_left_main_g; /* vs the frame */ rectangle full_right_main_g; /* vs the frame */ int left_end_length; int left_of_text_length; int right_end_length; int right_of_text_length; rotation_t draw_rotation; rotation_t restore_rotation; unsigned td_is_rotated : 1; unsigned has_been_saved : 1; unsigned has_vt : 1; /* vertical title ? */ unsigned has_an_upsidedown_rotation : 1; /* 270 || 180 */ } titlebar_descr; /* ---------------------------- forward declarations ----------------------- */ /* forward declarations are not so good */ /* for grouping titlebar_descr computation */ static void border_rotate_titlebar_descr(FvwmWindow *fw, titlebar_descr *td); /* for grouping the MultiPixmap stuff */ static Bool 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); /* ---------------------------- local variables ---------------------------- */ static const char ulgc[] = { 1, 0, 0, 0x7f, 2, 1, 1 }; static const char brgc[] = { 1, 1, 2, 0x7f, 0, 0, 3 }; /* ---------------------------- exported variables (globals) --------------- */ XGCValues Globalgcv; unsigned long Globalgcm; /* ---------------------------- local functions ---------------------------- */ static Bool is_button_toggled( FvwmWindow *fw, int button) { mwm_flags mf; if (!HAS_MWM_BUTTONS(fw)) { return False; } mf = TB_MWM_DECOR_FLAGS(GetDecor(fw, buttons[button])); if ((mf & MWM_DECOR_MAXIMIZE) && IS_MAXIMIZED(fw)) { return True; } if ((mf & MWM_DECOR_SHADE) && IS_SHADED(fw)) { return True; } if ((mf & MWM_DECOR_STICK) && (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw))) { return True; } if (TB_FLAGS(fw->decor->buttons[button]).has_layer && fw->layer == TB_LAYER(fw->decor->buttons[button])) { return True; } return False; } /* rules to get button state */ static ButtonState border_flags_to_button_state( int is_pressed, int is_lit, int is_toggled) { if (!is_lit && Scr.gs.use_inactive_buttons) { if (is_pressed && Scr.gs.use_inactive_down_buttons) { return (is_toggled) ? BS_ToggledInactiveDown : BS_InactiveDown; } else { return (is_toggled) ? BS_ToggledInactiveUp : BS_InactiveUp; } } else { if (is_pressed && Scr.gs.use_active_down_buttons) { return (is_toggled) ? BS_ToggledActiveDown : BS_ActiveDown; } else { return (is_toggled) ? BS_ToggledActiveUp : BS_ActiveUp; } } } static void get_common_decorations( common_decorations_type *cd, FvwmWindow *t, window_parts draw_parts, Bool has_focus, Bool is_border, Bool do_change_gcs) { DecorFace *df; color_quad *draw_colors; df = border_get_border_style(t, has_focus); cd->bg_border_cs = -1; cd->cs = -1; if (has_focus) { /* are we using textured borders? */ if (DFS_FACE_TYPE(df->style) == TiledPixmapButton && GetDecor(t, BorderStyle.active.u.p->depth) == Pdepth) { cd->texture_pixmap = GetDecor( t, BorderStyle.active.u.p->picture); cd->texture_pixmap_width = GetDecor( t, BorderStyle.active.u.p->width); cd->texture_pixmap_height = GetDecor( t, BorderStyle.active.u.p->height); } else if (DFS_FACE_TYPE(df->style) == ColorsetButton) { cd->bg_border_cs = GetDecor( t, BorderStyle.active.u.acs.cs); } cd->back_pixmap = Scr.gray_pixmap; if (is_border) { draw_colors = &(t->border_hicolors); cd->cs = t->border_cs_hi; } else { draw_colors = &(t->hicolors); cd->cs = t->cs_hi; } } else { if (DFS_FACE_TYPE(df->style) == TiledPixmapButton && GetDecor(t, BorderStyle.inactive.u.p->depth) == Pdepth) { cd->texture_pixmap = GetDecor( t, BorderStyle.inactive.u.p->picture); cd->texture_pixmap_width = GetDecor( t, BorderStyle.inactive.u.p->width); cd->texture_pixmap_height = GetDecor( t, BorderStyle.inactive.u.p->height); } else if (DFS_FACE_TYPE(df->style) == ColorsetButton) { cd->bg_border_cs = GetDecor( t, BorderStyle.inactive.u.acs.cs); } if (IS_STICKY_ACROSS_PAGES(t) || IS_STICKY_ACROSS_DESKS(t)) { cd->back_pixmap = Scr.sticky_gray_pixmap; } else { cd->back_pixmap = Scr.light_gray_pixmap; } if (is_border) { draw_colors = &(t->border_colors); cd->cs = t->border_cs; } else { draw_colors = &(t->colors); cd->cs = t->cs; } } cd->fore_color = draw_colors->fore; cd->back_color = draw_colors->back; if (do_change_gcs) { Globalgcv.foreground = draw_colors->hilight; Globalgcm = GCForeground; XChangeGC(dpy, Scr.ScratchGC1, Globalgcm, &Globalgcv); Globalgcv.foreground = draw_colors->shadow; XChangeGC(dpy, Scr.ScratchGC2, Globalgcm, &Globalgcv); cd->relief_gc = Scr.ScratchGC1; cd->shadow_gc = Scr.ScratchGC2; } /* MWMBorder style means thin 3d effects */ cd->relief_width = (HAS_MWM_BORDER(t) ? 1 : 2); if (cd->texture_pixmap) { cd->attributes.background_pixmap = cd->texture_pixmap; cd->valuemask = CWBackPixmap; } else { if (Pdepth < 2) { cd->attributes.background_pixmap = cd->back_pixmap; cd->valuemask = CWBackPixmap; } else { cd->attributes.background_pixel = cd->back_color; cd->valuemask = CWBackPixel; } } if (Pdepth < 2) { cd->notex_attributes.background_pixmap = cd->back_pixmap; cd->notex_valuemask = CWBackPixmap; } else { cd->notex_attributes.background_pixel = cd->back_color; cd->notex_valuemask = CWBackPixel; } return; } static window_parts border_get_changed_border_parts( FvwmWindow *fw, rectangle *old_sidebar_g, rectangle *new_sidebar_g, int cs) { window_parts changed_parts; changed_parts = PART_NONE; if (!CSET_IS_TRANSPARENT_PR(cs) && CSET_HAS_PIXMAP(cs) && (old_sidebar_g->x != new_sidebar_g->x || old_sidebar_g->y != new_sidebar_g->y || old_sidebar_g->width != new_sidebar_g->width || old_sidebar_g->height != new_sidebar_g->height)) { /* optimizable? */ changed_parts |= PART_FRAME; return changed_parts; } if (old_sidebar_g->x != new_sidebar_g->x) { changed_parts |= (PART_FRAME & (~PART_BORDER_W)); } if (old_sidebar_g->y != new_sidebar_g->y) { changed_parts |= (PART_FRAME & (~PART_BORDER_N)); } if (old_sidebar_g->width != new_sidebar_g->width) { changed_parts |= PART_BORDER_N | PART_BORDER_S; if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) == TiledPixmapButton) { changed_parts |= PART_BORDER_NE | PART_BORDER_E | PART_BORDER_SE; } } if (old_sidebar_g->height != new_sidebar_g->height) { changed_parts |= PART_BORDER_W | PART_BORDER_E; if (DFS_FACE_TYPE(GetDecor(fw, BorderStyle.active.style)) == TiledPixmapButton) { changed_parts |= PART_BORDER_SW | PART_BORDER_S | PART_BORDER_SE; } } return changed_parts; } static int 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) { window_parts draw_parts; window_parts parts_to_light; rectangle sidebar_g_old; DecorFaceStyle *borderstyle; Bool has_x_marks; Bool has_x_marks_old; Bool has_y_marks; Bool has_y_marks_old; int cs = cd->bg_border_cs; draw_parts = 0; borderstyle = (do_hilight) ? &GetDecor(fw, BorderStyle.active.style) : &GetDecor(fw, BorderStyle.inactive.style); frame_get_sidebar_geometry( fw, borderstyle, new_g, &br->sidebar_g, &has_x_marks, &has_y_marks); if (has_x_marks == True) { draw_parts |= PART_X_HANDLES; br->marks.has_x_marks = 1; } else { br->marks.has_x_marks = 0; } if (has_y_marks == True) { draw_parts |= PART_Y_HANDLES; br->marks.has_y_marks = 1; } else { br->marks.has_y_marks = 0; } draw_parts |= (pressed_parts ^ fw->decor_state.parts_inverted); parts_to_light = (do_hilight == True) ? PART_FRAME : PART_NONE; draw_parts |= (parts_to_light ^ fw->decor_state.parts_lit); draw_parts |= (~(fw->decor_state.parts_drawn) & PART_FRAME); draw_parts |= force_draw_parts; if (old_g == NULL) { old_g = &fw->g.frame; } if ((draw_parts & PART_FRAME) == PART_FRAME) { draw_parts |= PART_FRAME; return draw_parts; } frame_get_sidebar_geometry( fw, borderstyle, old_g, &sidebar_g_old, &has_x_marks_old, &has_y_marks_old); if (has_x_marks_old != has_x_marks) { draw_parts |= (PART_FRAME & (~(PART_BORDER_N | PART_BORDER_S))); } if (has_y_marks_old != has_y_marks) { draw_parts |= (PART_FRAME & (~(PART_BORDER_W | PART_BORDER_E))); } draw_parts |= border_get_changed_border_parts( fw, &sidebar_g_old, &br->sidebar_g, cs); draw_parts &= (PART_FRAME | PART_HANDLES); return draw_parts; } static window_parts border_get_tb_parts_to_draw( FvwmWindow *fw, titlebar_descr *td, rectangle *old_g, rectangle *new_g, window_parts force_draw_parts) { window_parts draw_parts; ButtonState old_state; int i; DecorFace *df,*tdf; td->tbstate.draw_bmask = 0; draw_parts = PART_NONE; /* first time? */ draw_parts |= (~(fw->decor_state.parts_drawn) & PART_TITLE); td->tbstate.draw_bmask |= (~(fw->decor_state.buttons_drawn)); /* forced? */ draw_parts |= force_draw_parts; td->tbstate.draw_bmask |= (force_draw_parts & PART_BUTTONS) ? ~0 : 0; /* check if state changed */ old_state = border_flags_to_button_state( (fw->decor_state.parts_inverted & PART_TITLE), (fw->decor_state.parts_lit & PART_TITLE), 0); if (old_state != td->tbstate.tstate) { draw_parts |= PART_TITLE; } /* size changed? */ if ((td->old_layout.title_g.width != td->layout.title_g.width || td->old_layout.title_g.height != td->layout.title_g.height) && td->layout.title_g.x >= 0 && td->layout.title_g.y >= 0) { draw_parts |= PART_TITLE; } /* same for buttons */ for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { unsigned int mask = (1 << i); if (FW_W_BUTTON(fw, i) == None) { continue; } old_state = border_flags_to_button_state( (fw->decor_state.buttons_inverted & mask), (fw->decor_state.buttons_lit & mask), (fw->decor_state.buttons_toggled & mask)); if (old_state != td->tbstate.bstate[i]) { draw_parts |= PART_BUTTONS; td->tbstate.draw_bmask |= mask; } if ((td->old_layout.button_g[i].width != td->layout.button_g[i].width || td->old_layout.button_g[i].height != td->layout.button_g[i].height) && td->layout.button_g[i].x >= 0 && td->layout.button_g[i].y >= 0) { draw_parts |= PART_BUTTONS; td->tbstate.draw_bmask |= mask; } } /* position changed and background is tiled or a cset? */ if ((draw_parts & PART_TITLE) == PART_NONE && td->layout.title_g.x >= 0 && td->layout.title_g.y >= 0) { df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate]; if (DFS_USE_BORDER_STYLE(df->style) && (((td->old_layout.title_g.x != td->layout.title_g.x || td->old_layout.title_g.y != td->layout.title_g.y) && ((td->cd->valuemask & CWBackPixmap) || CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs))) || (old_g->width != new_g->width && CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs)) || (old_g->height != new_g->height && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs)) || ((old_g->x != new_g->x || old_g->y != new_g->y) && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs)))) { draw_parts |= PART_TITLE; } if ((draw_parts & PART_TITLE) == PART_NONE && (old_g->x != new_g->x || old_g->y != new_g->y)) { for (tdf = df; tdf != NULL; tdf = tdf->next) { if (DFS_FACE_TYPE(tdf->style) == ColorsetButton && CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs)) { draw_parts |= PART_TITLE; break; } } } } for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { unsigned int mask; DecorFaceStyle *bs; mask = (1 << i); bs = &TB_STATE( GetDecor(fw, buttons[i]))[td->tbstate.bstate[i]].style; if ((td->tbstate.draw_bmask & mask) || td->layout.button_g[i].x < 0 || td->layout.button_g[i].y < 0) { continue; } if (DFS_USE_BORDER_STYLE(*bs) && (((td->old_layout.button_g[i].x != td->layout.button_g[i].x|| td->old_layout.button_g[i].y != td->layout.button_g[i].y) && ((td->cd->valuemask & CWBackPixmap) || CSET_PIXMAP_IS_TILED(td->cd->bg_border_cs))) || (old_g->width != new_g->width && CSET_PIXMAP_IS_X_STRETCHED(td->cd->bg_border_cs)) || (old_g->height != new_g->height && CSET_PIXMAP_IS_Y_STRETCHED(td->cd->bg_border_cs)) || ((old_g->x != new_g->x || old_g->y != new_g->y) && CSET_IS_TRANSPARENT_ROOT(td->cd->bg_border_cs)))) { td->tbstate.draw_bmask |= mask; } else if (DFS_USE_TITLE_STYLE(*bs)) { df = &TB_STATE(GetDecor( fw, titlebar))[td->tbstate.bstate[i]]; for(tdf = df; tdf != NULL; tdf = tdf->next) { int cs; if (DFS_FACE_TYPE(tdf->style) == MultiPixmap) { /* can be improved */ td->tbstate.draw_bmask |= mask; break; } if (DFS_FACE_TYPE(tdf->style) != ColorsetButton || !CSET_HAS_PIXMAP(tdf->u.acs.cs)) { continue; } cs = tdf->u.acs.cs; if(((td->old_layout.button_g[i].x != td->layout.button_g[i].x || td->old_layout.button_g[i].y != td->layout.button_g[i].y) || CSET_PIXMAP_IS_TILED(cs)) || (old_g->width != new_g->width && CSET_PIXMAP_IS_X_STRETCHED(cs)) || (old_g->height != new_g->height && CSET_PIXMAP_IS_Y_STRETCHED(cs)) || ((old_g->x != new_g->x || old_g->y != new_g->y) && CSET_IS_TRANSPARENT_ROOT(cs))) { td->tbstate.draw_bmask |= mask; break; } } } if (td->tbstate.draw_bmask & mask) { continue; } if (old_g->x != new_g->x || old_g->y != new_g->y) { df = &TB_STATE(GetDecor( fw, buttons[i]))[td->tbstate.bstate[i]]; for(tdf = df; tdf != NULL; tdf = tdf->next) { if (DFS_FACE_TYPE(tdf->style) == ColorsetButton && CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs)) { td->tbstate.draw_bmask |= mask; break; } } } } td->tbstate.max_bmask = 0; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (FW_W_BUTTON(fw, i) == None) { continue; } if ((i & 1) == 1 && i / 2 < Scr.nr_right_buttons) { td->tbstate.max_bmask |= (1 << i); } else if ((i & 1) == 0 && i / 2 < Scr.nr_left_buttons) { td->tbstate.max_bmask |= (1 << i); } } td->tbstate.draw_bmask &= td->tbstate.max_bmask; td->tbstate.pressed_bmask &= td->tbstate.max_bmask; td->tbstate.lit_bmask &= td->tbstate.max_bmask; td->tbstate.toggled_bmask &= td->tbstate.max_bmask; td->tbstate.clear_bmask &= td->tbstate.max_bmask; if (td->tbstate.draw_bmask == 0) { draw_parts &= ~PART_BUTTONS; } else { draw_parts |= PART_BUTTONS; } draw_parts &= PART_TITLEBAR; return draw_parts; } static void border_get_border_gcs( draw_border_gcs *ret_gcs, common_decorations_type *cd, FvwmWindow *fw, Bool do_hilight) { static GC transparent_gc = None; DecorFaceStyle *borderstyle; Bool is_reversed = False; if (transparent_gc == None && !HAS_NO_BORDER(fw) && !HAS_MWM_BORDER(fw)) { XGCValues xgcv; xgcv.function = GXnoop; xgcv.plane_mask = 0; transparent_gc = fvwmlib_XCreateGC( dpy, Scr.NoFocusWin, GCFunction | GCPlaneMask, &xgcv); } ret_gcs->transparent = transparent_gc; /* get the border style bits */ borderstyle = (do_hilight) ? &GetDecor(fw, BorderStyle.active.style) : &GetDecor(fw, BorderStyle.inactive.style); if (borderstyle->flags.button_relief == DFS_BUTTON_IS_SUNK) { is_reversed = True; } if (is_reversed) { ret_gcs->shadow = cd->relief_gc; ret_gcs->relief = cd->shadow_gc; } else { ret_gcs->relief = cd->relief_gc; ret_gcs->shadow = cd->shadow_gc; } return; } static void trim_border_layout( FvwmWindow *fw, DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr) { /* If the border is too thin to accomodate the standard look, we remove * parts of the border so that at least one pixel of the original * colour is visible. We make an exception for windows with a border * width of 2, though. */ if ((!IS_SHADED(fw) || HAS_TITLE(fw)) && fw->boundary_width == 2) { ret_size_descr->trim--; } if (ret_size_descr->trim < 0) { ret_size_descr->trim = 0; } for ( ; ret_size_descr->trim > 0; ret_size_descr->trim--) { if (ret_size_descr->w_hiout > 1) { ret_size_descr->w_hiout--; } else if (ret_size_descr->w_shin > 0) { ret_size_descr->w_shin--; } else if (ret_size_descr->w_hiout > 0) { ret_size_descr->w_hiout--; } else if (ret_size_descr->w_trout > 0) { ret_size_descr->w_trout = 0; ret_size_descr->w_trin = 0; ret_size_descr->w_din = 0; ret_size_descr->w_hiout = 1; } ret_size_descr->sum--; } ret_size_descr->w_c = fw->boundary_width - ret_size_descr->sum; return; } static void check_remove_inset( DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr) { if (!DFS_HAS_NO_INSET(*borderstyle)) { return; } ret_size_descr->w_shin = 0; ret_size_descr->sum--; ret_size_descr->trim--; if (ret_size_descr->w_trin) { ret_size_descr->w_trout = 0; ret_size_descr->w_trin = 0; ret_size_descr->w_din = 0; ret_size_descr->w_hiout = 1; ret_size_descr->sum -= 2; ret_size_descr->trim -= 2; } return; } static void border_fetch_mwm_layout( FvwmWindow *fw, DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr) { /* MWM borders look like this: * * HHCCCCS from outside to inside on the left and top border * SSCCCCH from outside to inside on the bottom and right border * ||||||| * |||||||__ w_shin (inner shadow area) * ||||||___ w_c (transparent area) * |||||____ w_c (transparent area) * ||||_____ w_c (transparent area) * |||______ w_c (transparent area) * ||_______ w_hiout (outer hilight area) * |________ w_hiout (outer hilight area) * * * C = original colour * H = hilight * S = shadow */ ret_size_descr->w_dout = 0; ret_size_descr->w_hiout = 2; ret_size_descr->w_trout = 0; ret_size_descr->w_trin = 0; ret_size_descr->w_shin = 1; ret_size_descr->w_din = 0; ret_size_descr->sum = 3; ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width + 1; check_remove_inset(borderstyle, ret_size_descr); trim_border_layout(fw, borderstyle, ret_size_descr); return; } static void border_fetch_fvwm_layout( FvwmWindow *fw, DecorFaceStyle *borderstyle, border_relief_size_descr *ret_size_descr) { /* Fvwm borders look like this: * * SHHCCSS from outside to inside on the left and top border * SSCCHHS from outside to inside on the bottom and right border * ||||||| * |||||||__ w_din (inner dark area) * ||||||___ w_shin (inner shadow area) * |||||____ w_trin (inner transparent/shadow area) * ||||_____ w_c (transparent area) * |||______ w_trout (outer transparent/hilight area) * ||_______ w_hiout (outer hilight area) * |________ w_dout (outer dark area) * * C = original colour * H = hilight * S = shadow * * reduced to 5 pixels it looks like this: * * SHHCS * SSCHS * ||||| * |||||__ w_din (inner dark area) * ||||___ w_trin (inner transparent/shadow area) * |||____ w_trout (outer transparent/hilight area) * ||_____ w_hiout (outer hilight area) * |______ w_dout (outer dark area) */ ret_size_descr->w_dout = 1; ret_size_descr->w_hiout = 1; ret_size_descr->w_trout = 1; ret_size_descr->w_trin = 1; ret_size_descr->w_shin = 1; ret_size_descr->w_din = 1; /* w_trout + w_trin counts only as one pixel of border because * they let one pixel of the original colour shine through. */ ret_size_descr->sum = 6; ret_size_descr->trim = ret_size_descr->sum - fw->boundary_width; check_remove_inset(borderstyle, ret_size_descr); trim_border_layout(fw, borderstyle, ret_size_descr); return; } static void border_get_border_relief_size_descr( border_relief_size_descr *ret_size_descr, FvwmWindow *fw, Bool do_hilight) { DecorFaceStyle *borderstyle; if (is_window_border_minimal(fw)) { /* the border is too small, only a background but no relief */ ret_size_descr->is_flat = 1; return; } borderstyle = (do_hilight) ? &GetDecor(fw, BorderStyle.active.style) : &GetDecor(fw, BorderStyle.inactive.style); if (borderstyle->flags.button_relief == DFS_BUTTON_IS_FLAT) { ret_size_descr->is_flat = 1; return; } ret_size_descr->is_flat = 0; /* get the relief layout */ if (HAS_MWM_BORDER(fw)) { border_fetch_mwm_layout(fw, borderstyle, ret_size_descr); } else { border_fetch_fvwm_layout(fw, borderstyle, ret_size_descr); } return; } static void border_get_border_marks_descr( common_decorations_type *cd, border_relief_descr *br, FvwmWindow *fw) { int inset; /* get mark's length and thickness */ inset = (br->relief.w_shin != 0 || br->relief.w_din != 0); br->marks.length = fw->boundary_width - br->relief.w_dout - inset; if (br->marks.length <= 0) { br->marks.has_x_marks = 0; br->marks.has_y_marks = 0; return; } br->marks.thickness = cd->relief_width; if (br->marks.thickness > br->marks.length) { br->marks.thickness = br->marks.length; } /* get offsets from outer side of window */ br->marks.offset_tl = br->relief.w_dout; br->marks.offset_br = -br->relief.w_dout - br->marks.length - br->marks.offset_tl; return; } static Pixmap border_create_decor_pixmap( common_decorations_type *cd, rectangle *decor_g) { Pixmap p; p = XCreatePixmap( dpy, Scr.Root, decor_g->width, decor_g->height, Pdepth); return p; } static void border_draw_part_relief( border_relief_descr *br, rectangle *frame_g, rectangle *part_g, Pixmap dest_pix, Bool is_inverted) { int i; int off_x = 0; int off_y = 0; int width = frame_g->width - 1; int height = frame_g->height - 1; int w[7]; GC gc[4]; w[0] = br->relief.w_dout; w[1] = br->relief.w_hiout; w[2] = br->relief.w_trout; w[3] = br->relief.w_c; w[4] = br->relief.w_trin; w[5] = br->relief.w_shin; w[6] = br->relief.w_din; gc[(is_inverted == True)] = br->gcs.relief; gc[!(is_inverted == True)] = br->gcs.shadow; gc[2] = br->gcs.transparent; gc[3] = br->gcs.shadow; off_x = -part_g->x; off_y = -part_g->y; width = frame_g->width - 1; height = frame_g->height - 1; for (i = 0; i < 7; i++) { if (ulgc[i] != 0x7f && w[i] > 0) { do_relieve_rectangle( dpy, dest_pix, off_x, off_y, width, height, gc[(int)ulgc[i]], gc[(int)brgc[i]], w[i], False); } off_x += w[i]; off_y += w[i]; width -= 2 * w[i]; height -= 2 * w[i]; } return; } static void border_draw_x_mark( border_relief_descr *br, int x, int y, Pixmap dest_pix, Bool do_draw_shadow) { int k; int length; GC gc; if (br->marks.has_x_marks == 0) { return; } x += br->marks.offset_tl; gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief; /* draw it */ for (k = 0, length = br->marks.length - 1; k < br->marks.thickness; k++, length--) { int x1; int x2; int y1; int y2; if (length < 0) { break; } if (do_draw_shadow) { x1 = x + k; y1 = y - 1 - k; } else { x1 = x; y1 = y + k; } x2 = x1 + length; y2 = y1; XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2); } return; } static void border_draw_y_mark( border_relief_descr *br, int x, int y, Pixmap dest_pix, Bool do_draw_shadow) { int k; int length; GC gc; if (br->marks.has_y_marks == 0) { return; } y += br->marks.offset_tl; gc = (do_draw_shadow) ? br->gcs.shadow : br->gcs.relief; /* draw it */ for (k = 0, length = br->marks.length; k < br->marks.thickness; k++, length--) { int x1; int x2; int y1; int y2; if (length <= 0) { break; } if (do_draw_shadow) { x1 = x - 1 - k; y1 = y + k; } else { x1 = x + k; y1 = y; } x2 = x1; y2 = y1 + length - 1; XDrawLine(dpy, dest_pix, gc, x1, y1, x2, y2); } return; } static void border_draw_part_marks( border_relief_descr *br, rectangle *part_g, window_parts part, Pixmap dest_pix) { int l; int t; int w; int h; int o; l = br->sidebar_g.x; t = br->sidebar_g.y; w = part_g->width; h = part_g->height; o = br->marks.offset_br; switch (part) { case PART_BORDER_N: border_draw_y_mark(br, 0, 0, dest_pix, False); border_draw_y_mark(br, w, 0, dest_pix, True); break; case PART_BORDER_S: border_draw_y_mark(br, 0, h + o, dest_pix, False); border_draw_y_mark(br, w, h + o, dest_pix, True); break; case PART_BORDER_E: border_draw_x_mark(br, w + o, 0, dest_pix, False); border_draw_x_mark(br, w + o, h, dest_pix, True); break; case PART_BORDER_W: border_draw_x_mark(br, 0, 0, dest_pix, False); border_draw_x_mark(br, 0, h, dest_pix, True); break; case PART_BORDER_NW: border_draw_x_mark(br, 0, t, dest_pix, True); border_draw_y_mark(br, l, 0, dest_pix, True); break; case PART_BORDER_NE: border_draw_x_mark(br, l + o, t, dest_pix, True); border_draw_y_mark(br, 0, 0, dest_pix, False); break; case PART_BORDER_SW: border_draw_x_mark(br, 0, 0, dest_pix, False); border_draw_y_mark(br, l, t + o, dest_pix, True); break; case PART_BORDER_SE: border_draw_x_mark(br, l + o, 0, dest_pix, False); border_draw_y_mark(br, 0, t + o, dest_pix, False); break; default: return; } return; } inline static void border_set_part_background( Window w, Pixmap pix) { XSetWindowAttributes xswa; xswa.background_pixmap = pix; XChangeWindowAttributes(dpy, w, CWBackPixmap, &xswa); return; } /* render the an image into the pixmap */ static void border_fill_pixmap_background( Pixmap dest_pix, rectangle *dest_g, pixmap_background_type *bg, common_decorations_type *cd) { Bool do_tile; Bool do_stretch; XGCValues xgcv; unsigned long valuemask; Pixmap p = None, shape = None, alpha = None; int src_width, src_height; do_tile = (bg->flags.use_pixmap && bg->pixmap.flags.is_tiled) ? True : False; do_stretch = (bg->flags.use_pixmap && bg->pixmap.flags.is_stretched) ? True : False; xgcv.fill_style = FillSolid; valuemask = GCFillStyle; if (!bg->flags.use_pixmap) { /* solid pixel */ xgcv.foreground = bg->pixel; xgcv.clip_x_origin = 0; xgcv.clip_y_origin = 0; xgcv.clip_mask = None; valuemask |= GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin; XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv); XFillRectangle( dpy, dest_pix, Scr.BordersGC, dest_g->x, dest_g->y, dest_g->width - dest_g->x, dest_g->height - dest_g->y); return; } if (do_stretch) { if (bg->pixmap.p) { p = CreateStretchPixmap( dpy, bg->pixmap.p, bg->pixmap.g.width, bg->pixmap.g.height, bg->pixmap.depth, bg->pixmap.stretch_w, bg->pixmap.stretch_h, (bg->pixmap.depth == 1)? Scr.MonoGC:Scr.BordersGC); } if (bg->pixmap.shape) { shape = CreateStretchPixmap( dpy, bg->pixmap.shape, bg->pixmap.g.width, bg->pixmap.g.height, 1, bg->pixmap.stretch_w, bg->pixmap.stretch_h, Scr.MonoGC); } if (bg->pixmap.alpha) { alpha = CreateStretchPixmap( dpy, bg->pixmap.alpha, bg->pixmap.g.width, bg->pixmap.g.height, FRenderGetAlphaDepth(), bg->pixmap.stretch_w, bg->pixmap.stretch_h, Scr.AlphaGC); } src_width = bg->pixmap.stretch_w; src_height = bg->pixmap.stretch_h; } else { p = bg->pixmap.p; shape = bg->pixmap.shape; alpha = bg->pixmap.alpha; src_width = bg->pixmap.g.width; src_height = bg->pixmap.g.height; } if (do_tile == False) { /* pixmap, offset stored in dest_g->x/y */ xgcv.foreground = cd->fore_color; xgcv.background = cd->back_color; valuemask |= GCForeground|GCBackground; XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv); PGraphicsRenderPixmaps( dpy, Scr.NoFocusWin, p, shape, alpha, bg->pixmap.depth, &(bg->pixmap.fra), dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC, bg->pixmap.g.x, bg->pixmap.g.y, src_width, src_height, dest_g->x, dest_g->y, dest_g->width - dest_g->x, dest_g->height - dest_g->y, False); } else { /* tiled pixmap */ xgcv.foreground = cd->fore_color; xgcv.background = cd->back_color; valuemask |= GCForeground|GCBackground; XChangeGC(dpy, Scr.BordersGC, valuemask, &xgcv); PGraphicsRenderPixmaps( dpy, Scr.NoFocusWin, p, shape, alpha, bg->pixmap.depth, &(bg->pixmap.fra), dest_pix, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC, bg->pixmap.g.x, bg->pixmap.g.y, src_width, src_height, dest_g->x, dest_g->y, dest_g->width - dest_g->x, dest_g->height - dest_g->y, True); } if (p && p != bg->pixmap.p) { XFreePixmap(dpy, p); } if (shape && shape != bg->pixmap.shape) { XFreePixmap(dpy, shape); } if (alpha && alpha != bg->pixmap.alpha) { XFreePixmap(dpy, alpha); } return; } /* create a root transparent colorset bg, we take in account a possible * drawing rotation */ static Pixmap border_create_root_transparent_pixmap( titlebar_descr *td, Window w, int width, int height, int cs) { int my_w, my_h; Pixmap p; if (!CSET_IS_TRANSPARENT_ROOT(cs)) { return None; } if (td->td_is_rotated && (td->draw_rotation == ROTATION_90 || td->draw_rotation == ROTATION_270)) { my_h = width; my_w = height; } else { my_w = width; my_h = height; } p = CreateBackgroundPixmap( dpy, w, my_w, my_h, &Colorset[cs], Pdepth, Scr.BordersGC, False); if (p && td->td_is_rotated) { Pixmap tmp; tmp = CreateRotatedPixmap( dpy, p, my_w, my_h, Pdepth, Scr.BordersGC, td->restore_rotation); XFreePixmap(dpy, p); p = tmp; } return p; } static void border_get_frame_pixmap( common_decorations_type *cd, rectangle *frame_g) { dynamic_common_decorations *dcd = &(cd->dynamic_cd); if (dcd->frame_pixmap != None) { /* should not happen */ fprintf(stderr, "Bad use of border_get_frame_pixmap!!\n"); dcd->frame_pixmap = None; } if (cd->bg_border_cs < 0 || CSET_IS_TRANSPARENT(cd->bg_border_cs)) { /* should not happen */ } else { dcd->frame_pixmap = CreateBackgroundPixmap( dpy, Scr.NoFocusWin, frame_g->width, frame_g->height, &Colorset[cd->bg_border_cs], Pdepth, Scr.BordersGC, False); } return; } static void border_get_border_background( pixmap_background_type *bg, common_decorations_type *cd, rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window w) { *free_bg_pixmap = False; if (cd->texture_pixmap) { bg->flags.use_pixmap = 1; bg->pixmap.p = cd->texture_pixmap; bg->pixmap.g.width = cd->texture_pixmap_width; bg->pixmap.g.height = cd->texture_pixmap_height; bg->pixmap.shape = None; bg->pixmap.alpha = None; bg->pixmap.depth = Pdepth; bg->pixmap.flags.is_tiled = 1; bg->pixmap.flags.is_stretched = 0; bg->pixmap.fra.mask = 0; } else if (cd->bg_border_cs >= 0 && !CSET_IS_TRANSPARENT_PR(cd->bg_border_cs)) { colorset_t *cs_t = &Colorset[cd->bg_border_cs]; XGCValues xgcv; if (CSET_IS_TRANSPARENT_ROOT(cd->bg_border_cs)) { bg->pixmap.p = CreateBackgroundPixmap( dpy, w, part_g->width, part_g->height, cs_t, Pdepth, Scr.BordersGC, False); } else { /* FIXME */ if (cd->dynamic_cd.frame_pixmap == None) { border_get_frame_pixmap(cd, relative_g); } bg->pixmap.p = XCreatePixmap( dpy, cd->dynamic_cd.frame_pixmap, part_g->width, part_g->height, Pdepth); xgcv.fill_style = FillTiled; xgcv.tile = cd->dynamic_cd.frame_pixmap; xgcv.ts_x_origin = - relative_g->x; xgcv.ts_y_origin = - relative_g->y; XChangeGC( dpy, Scr.BordersGC, GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle, &xgcv); XFillRectangle( dpy, bg->pixmap.p, Scr.BordersGC, 0, 0, part_g->width, part_g->height); xgcv.fill_style = FillSolid; XChangeGC(dpy, Scr.BordersGC, GCFillStyle, &xgcv); } bg->pixmap.g.width = part_g->width; bg->pixmap.g.height = part_g->height; bg->flags.use_pixmap = 1; bg->pixmap.shape = None; bg->pixmap.alpha = None; bg->pixmap.depth = Pdepth; bg->pixmap.flags.is_tiled = 1; bg->pixmap.flags.is_stretched = 0; bg->pixmap.fra.mask = 0; *free_bg_pixmap = True; } else { bg->flags.use_pixmap = 0; bg->pixel = cd->attributes.background_pixel; } return; } static void 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) { pixmap_background_type bg; rectangle part_g; rectangle pix_g; rectangle relative_g; Pixmap p; Window w; Bool free_bg_pixmap = False; /* make a pixmap */ border_get_part_geometry(fw, part, sidebar_g, &part_g, &w); if (part_g.width <= 0 || part_g.height <= 0) { return; } p = border_create_decor_pixmap(cd, &part_g); /* set the background tile */ relative_g.width = fw->g.frame.width; relative_g.height = fw->g.frame.height; relative_g.x = part_g.x; relative_g.y = part_g.y; border_get_border_background( &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w); if (cd->texture_pixmap) { switch (part) { case PART_BORDER_E: bg.pixmap.g.x = frame_g->width - fw->boundary_width; break; case PART_BORDER_NE: case PART_BORDER_SE: bg.pixmap.g.x = frame_g->width - fw->corner_width; break; case PART_BORDER_N: case PART_BORDER_S: bg.pixmap.g.x = fw->corner_width; break; default: bg.pixmap.g.x = 0; break; } switch (part) { case PART_BORDER_S: bg.pixmap.g.y = frame_g->height - fw->boundary_width; break; case PART_BORDER_SW: case PART_BORDER_SE: bg.pixmap.g.y = frame_g->height - fw->corner_width; break; case PART_BORDER_W: case PART_BORDER_E: bg.pixmap.g.y = fw->corner_width; break; default: bg.pixmap.g.y = 0; break; } } else { bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; } /* set the geometry for drawing the Tiled pixmap; maybe add the relief * as offset? */ pix_g.x = 0; pix_g.y = 0; pix_g.width = part_g.width; pix_g.height = part_g.height; border_fill_pixmap_background(p, &pix_g, &bg, cd); if (free_bg_pixmap && bg.pixmap.p) { XFreePixmap(dpy, bg.pixmap.p); } /* draw the relief over the background */ if (!br->relief.is_flat) { border_draw_part_relief(br, frame_g, &part_g, p, is_inverted); /* draw the handle marks */ if (br->marks.has_x_marks || br->marks.has_y_marks) { border_draw_part_marks(br, &part_g, part, p); } } /* apply the pixmap and destroy it */ border_set_part_background(w, p); if (do_clear == True) { XClearWindow(dpy,w); } XFreePixmap(dpy, p); return; } static void 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) { window_parts part; window_parts draw_handles; /* get the description of the drawing directives */ border_get_border_relief_size_descr(&br->relief, fw, do_hilight); border_get_border_marks_descr(cd, br, fw); /* fetch the gcs used to draw the border */ border_get_border_gcs(&br->gcs, cd, fw, do_hilight); /* draw everything in a big loop */ draw_parts &= (PART_FRAME | PART_HANDLES); draw_handles = (draw_parts & PART_HANDLES); for (part = PART_BORDER_N; (part & PART_FRAME); part <<= 1) { if (part & draw_parts) { border_draw_one_border_part( cd, fw, &br->sidebar_g, frame_g, br, part, draw_handles, (pressed_parts & part) ? True : False, do_clear); } } return; } /* * * Draws a little pattern within a window (more complex) * */ static void border_draw_vector_to_pixmap( Pixmap dest_pix, common_decorations_type *cd, int is_toggled, struct vector_coords *coords, rectangle *pixmap_g) { GC gcs[4]; int i; if (coords->use_fgbg == 1) { Globalgcv.foreground = cd->fore_color; Globalgcm = GCForeground; XChangeGC(dpy, Scr.ScratchGC3, Globalgcm, &Globalgcv); Globalgcv.foreground = cd->back_color; XChangeGC(dpy, Scr.ScratchGC4, Globalgcm, &Globalgcv); gcs[3] = Scr.ScratchGC3; /* @3 is fg */ gcs[2] = Scr.ScratchGC4; /* @2 is bg */ } if (is_toggled) { gcs[0] = cd->relief_gc; gcs[1] = cd->shadow_gc; } else { gcs[0] = cd->shadow_gc; gcs[1] = cd->relief_gc; } for (i = 1; i < coords->num; i++) { if (coords->c[i] < 0 || coords->c[i] >= 4) { /* don't draw a line */ continue; } XDrawLine( dpy, dest_pix, gcs[coords->c[i]], pixmap_g->width * coords->x[i-1] / 100 + coords->xoff[i-1], pixmap_g->height * coords->y[i-1] / 100 + coords->yoff[i-1], pixmap_g->width * coords->x[i] / 100 + coords->xoff[i], pixmap_g->height * coords->y[i] / 100 + coords->yoff[i]); } return; } /* * * Handle Title pixmaps used for UseTitleStyle * */ static void border_setup_bar_pixmaps( titlebar_descr *td, dynamic_common_decorations *dcd, DecorFace *df, ButtonState bs) { int count = dcd->bar_pixmaps[bs].count; DecorFace *tsdf; int i, j, mp_part_left, mp_part_right; if (count != 0) { /* ok */ return; } for (tsdf = df; tsdf != NULL; tsdf = tsdf->next) { if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton) { count++; } else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap) { border_mp_get_use_title_style_parts_and_geometry( td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs, tsdf->u.mp.solid_flags, True, NULL, &mp_part_left); border_mp_get_use_title_style_parts_and_geometry( td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs, tsdf->u.mp.solid_flags, False, NULL, &mp_part_right); for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++) { if (j != mp_part_left && j != mp_part_right) { continue; } if (tsdf->u.mp.acs[j].cs >= 0 || tsdf->u.mp.pixmaps[j]) { count++; } } } } if (count == 0) { dcd->bar_pixmaps[bs].count = -1; return; } else { dcd->bar_pixmaps[bs].bps = (bar_pixmap *)safemalloc(count*sizeof(bar_pixmap)); } dcd->bar_pixmaps[bs].count = count; i = 0; for (tsdf = df; tsdf != NULL; tsdf = tsdf->next) { if (DFS_FACE_TYPE(tsdf->style) == ColorsetButton) { dcd->bar_pixmaps[bs].bps[i].p = None; dcd->bar_pixmaps[bs].bps[i].mp_created_pic = NULL; dcd->bar_pixmaps[bs].bps[i].cs = tsdf->u.acs.cs; dcd->bar_pixmaps[bs].bps[i].mp_pic = NULL; dcd->bar_pixmaps[bs].bps[i].created = 0; dcd->bar_pixmaps[bs].bps[i].mp_part = TBMP_NONE; i++; } else if (DFS_FACE_TYPE(tsdf->style) == MultiPixmap) { border_mp_get_use_title_style_parts_and_geometry( td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs, tsdf->u.mp.solid_flags, True, NULL, &mp_part_left); border_mp_get_use_title_style_parts_and_geometry( td, tsdf->u.mp.pixmaps, tsdf->u.mp.acs, tsdf->u.mp.solid_flags, False, NULL, &mp_part_right); for (j = 0; j < UTS_TBMP_NUM_PIXMAPS; j++) { if (j != mp_part_left && j != mp_part_right) { continue; } if (tsdf->u.mp.acs[j].cs >= 0 || tsdf->u.mp.pixmaps[j]) { dcd->bar_pixmaps[bs].bps[i].p = None; dcd->bar_pixmaps[bs].bps[i]. mp_created_pic = NULL; dcd->bar_pixmaps[bs].bps[i].cs = tsdf->u.mp.acs[j].cs; dcd->bar_pixmaps[bs].bps[i].mp_pic = tsdf->u.mp.pixmaps[j]; dcd->bar_pixmaps[bs].bps[i].created = 0; dcd->bar_pixmaps[bs].bps[i].mp_part = j; i++; } } } } } static Pixmap 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) { ButtonState b; int i,j; int count = dcd->bar_pixmaps[bs].count; if (count <= 0) { return None; } i = 0; while(i < count && (dcd->bar_pixmaps[bs].bps[i].cs != cset || dcd->bar_pixmaps[bs].bps[i].mp_part != mp_part || dcd->bar_pixmaps[bs].bps[i].mp_pic != mp_pic)) { i++; } if (i == count) { return None; } if (mp_ret_pic) { *mp_ret_pic = dcd->bar_pixmaps[bs].bps[i].mp_created_pic; } if (dcd->bar_pixmaps[bs].bps[i].p == None) { /* see if we have it */ b = 0; while (b < BS_MaxButtonState) { int c = dcd->bar_pixmaps[b].count; j = 0; while(j < c && (dcd->bar_pixmaps[b].bps[j].cs != cset || dcd->bar_pixmaps[b].bps[j].mp_part != mp_part || dcd->bar_pixmaps[b].bps[j].mp_pic != mp_pic)) { j++; } if (j < c && dcd->bar_pixmaps[b].bps[j].p) { dcd->bar_pixmaps[bs].bps[i].p = dcd->bar_pixmaps[b].bps[j].p; if (mp_pic && mp_ret_pic) { *mp_ret_pic = dcd->bar_pixmaps[bs].bps[i]. mp_created_pic = dcd->bar_pixmaps[b].bps[j]. mp_created_pic; } break; } b++; } } if (dcd->bar_pixmaps[bs].bps[i].p == None) { if (cset >= 0) { dcd->bar_pixmaps[bs].bps[i].p = CreateBackgroundPixmap( dpy, Scr.NoFocusWin, bar_g->width, bar_g->height, &Colorset[cset], Pdepth, Scr.BordersGC, False); dcd->bar_pixmaps[bs].bps[i].created = True; } else if (mp_pic && mp_ret_pic) { if (stretch) { dcd->bar_pixmaps[bs].bps[i].mp_created_pic = PGraphicsCreateStretchPicture( dpy, Scr.NoFocusWin, mp_pic, bar_g->width, bar_g->height, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC); } else { dcd->bar_pixmaps[bs].bps[i].mp_created_pic = PGraphicsCreateTiledPicture( dpy, Scr.NoFocusWin, mp_pic, bar_g->width, bar_g->height, Scr.BordersGC, Scr.MonoGC, Scr.AlphaGC); } if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic) { dcd->bar_pixmaps[bs].bps[i].created = True; *mp_ret_pic = dcd->bar_pixmaps[bs].bps[i]. mp_created_pic; dcd->bar_pixmaps[bs].bps[i].p = dcd->bar_pixmaps[bs].bps[i]. mp_created_pic->picture; } } } return dcd->bar_pixmaps[bs].bps[i].p; } static void border_free_bar_pixmaps( dynamic_common_decorations *dcd) { ButtonState bs; int i; for (bs = 0; bs < BS_MaxButtonState; bs++) { if (dcd->bar_pixmaps[bs].count < 1) { continue; } for (i = 0; i < dcd->bar_pixmaps[bs].count; i++) { if (dcd->bar_pixmaps[bs].bps[i].mp_created_pic && dcd->bar_pixmaps[bs].bps[i].created) { PDestroyFvwmPicture( dpy, dcd->bar_pixmaps[bs].bps[i]. mp_created_pic); } else if (dcd->bar_pixmaps[bs].bps[i].p != None && dcd->bar_pixmaps[bs].bps[i].created) { XFreePixmap( dpy, dcd->bar_pixmaps[bs].bps[i].p); } } free(dcd->bar_pixmaps[bs].bps); } } /* * * MultiPixmap (aka, fancy title bar) (tril@igs.net) * */ #define TBMP_HAS_PART(p, pm, acs, sf) \ (pm[p] || acs[p].cs >= 0 || (sf & (1 << p))) /* Tile or stretch src into dest, starting at the given location and * continuing for the given width and height. This is a utility function used * by border_mp_draw_mp_titlebar. (tril@igs.net) */ static void 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) { int x = 0; int y = 0; pixmap_background_type bg; rectangle dest_g; dynamic_common_decorations *dcd; dcd = &cd->dynamic_cd; /* setup some default */ bg.pixmap.fra.mask = 0; bg.pixmap.flags.is_stretched = 0; bg.pixmap.flags.is_tiled = 0; bg.flags.use_pixmap = 1; bg.pixmap.p = bg.pixmap.alpha = bg.pixmap.shape = None; bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; dest_g.width = g->width + g->x; dest_g.height = g->height + g->y; dest_g.x = g->x; dest_g.y = g->y; if (solid_flags & (1 << part)) { bg.flags.use_pixmap = 0; bg.pixel = pixels[part]; border_fill_pixmap_background(dest, &dest_g, &bg, cd); return; } else if (acs[part].cs >= 0) { Pixmap p = None; bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA; bg.pixmap.fra.added_alpha_percent = acs[part].alpha_percent; if (CSET_IS_TRANSPARENT_PR(acs[part].cs)) { return; } if (CSET_IS_TRANSPARENT_ROOT(acs[part].cs)) { p = border_create_root_transparent_pixmap( td, w, g->width + g->x, g->height + g->y, acs[part].cs); bg.pixmap.p = p; bg.pixmap.depth = Pdepth; bg.pixmap.g.width = g->width; bg.pixmap.g.height = g->height; bg.pixmap.g.x = g->x; bg.pixmap.g.y = g->y; } else if (full_g != NULL) { bg.pixmap.p = border_get_bar_pixmaps( dcd, full_g, bs, acs[part].cs, NULL, part, (stretch_flags & (1 << part)), NULL); if (bg.pixmap.p) { if (part != TBMP_RIGHT_MAIN) { /* left buttons offset */ x = title_g->x - full_g->x; y = title_g->y - full_g->y; } bg.pixmap.g.width = full_g->width; bg.pixmap.g.height = full_g->height; bg.pixmap.flags.is_tiled = 1; bg.pixmap.g.x = x; bg.pixmap.g.y = y; bg.pixmap.depth = Pdepth; } } if (!bg.pixmap.p) { int bg_w, bg_h; p = CreateBackgroundPixmap( dpy, w, g->width, g->height, &Colorset[acs[part].cs], Pdepth, Scr.BordersGC, False); bg.pixmap.p = p; GetWindowBackgroundPixmapSize( &Colorset[acs[part].cs], g->width, g->height, &bg_w, &bg_h); bg.pixmap.g.width = bg_w; bg.pixmap.g.height = bg_h; bg.pixmap.depth = Pdepth; bg.pixmap.flags.is_tiled = 1; } if (bg.pixmap.p) { border_fill_pixmap_background(dest, &dest_g, &bg, cd); } if (p) { XFreePixmap(dpy, p); } } else if (src[part]) { FvwmPicture *full_pic = NULL; Pixmap p; if (full_g != NULL) { p = border_get_bar_pixmaps( dcd, full_g, bs, -1, src[part], part, (stretch_flags & (1 << part)), &full_pic); if (p && full_pic) { if (part != TBMP_RIGHT_MAIN) { /* left buttons offset */ x = title_g->x - full_g->x; y = title_g->y - full_g->y; } bg.pixmap.p = full_pic->picture; bg.pixmap.shape = full_pic->mask; bg.pixmap.alpha = full_pic->alpha; bg.pixmap.depth = full_pic->depth; bg.pixmap.g.width = full_pic->width; bg.pixmap.g.height = full_pic->height; bg.pixmap.g.x = x; bg.pixmap.g.y = y; } } if (!bg.pixmap.p) { if (stretch_flags & (1 << part)) { bg.pixmap.flags.is_stretched = 1; } else { bg.pixmap.flags.is_tiled = 1; } bg.pixmap.p = src[part]->picture; bg.pixmap.shape = src[part]->mask; bg.pixmap.alpha = src[part]->alpha; bg.pixmap.depth = src[part]->depth; bg.pixmap.g.width = src[part]->width; bg.pixmap.g.height = src[part]->height; bg.pixmap.stretch_w = dest_g.width - dest_g.x; bg.pixmap.stretch_h = dest_g.height - dest_g.y; } if (bg.pixmap.p) { border_fill_pixmap_background(dest, &dest_g, &bg, cd); } } return; } static int border_mp_get_length( titlebar_descr *td, FvwmPicture **pm, FvwmAcs *acs, unsigned int solid_flags, int part) { if (acs[part].cs >= 0 || (solid_flags & (1 << part))) { /* arbitrary */ if (td->has_vt) { return td->bar_g.width/2; } else { return td->bar_g.height/2; } } if (pm[part] == NULL) { return 0; } else if (td->has_vt) { return pm[part]->height; } else { return pm[part]->width; } } /* geometries relatively to the frame */ static void border_mp_get_titlebar_descr( FvwmWindow *fw, titlebar_descr *td, DecorFace *df) { DecorFace *tsdf; FvwmPicture **pm; FvwmAcs *acs; int add,tmpi; int left_of_text = 0; int right_of_text = 0; int left_end = 0; int right_end = 0; int before_space, after_space, under_offset, under_width; Bool has_mp = False; JustificationType just; unsigned short sf; int is_start = 0; just = TB_JUSTIFICATION(GetDecor(fw, titlebar)); /* first compute under text width */ if (td->length > 0) { under_width = td->length + 2*TBMP_TITLE_PADDING; } else { under_width = 0; } if (under_width > fw->title_length) { under_width = fw->title_length; td->offset = (fw->title_length - td->length) / 2; just = JUST_CENTER; } for (tsdf = df; tsdf != NULL; tsdf = tsdf->next) { if (tsdf->style.face_type != MultiPixmap) { continue; } has_mp = True; acs = tsdf->u.mp.acs; pm = tsdf->u.mp.pixmaps; sf = tsdf->u.mp.solid_flags; add = border_mp_get_length( td, pm, acs, sf, TBMP_LEFT_OF_TEXT); if (add > left_of_text && add + left_end + right_of_text + right_end + under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length) { left_of_text = add; } add = border_mp_get_length( td, pm, acs, sf, TBMP_RIGHT_OF_TEXT); if (add > right_of_text && add + left_end + left_of_text + right_end + under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length) { right_of_text = add; } add = border_mp_get_length( td, pm, acs, sf, TBMP_LEFT_END); if (add > left_end && add + right_of_text + left_of_text + right_end + under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length) { left_end = add; } add = border_mp_get_length( td, pm, acs, sf, TBMP_RIGHT_END); if (add > right_end && add + right_of_text + left_of_text + left_end + under_width + 2*TBMP_MIN_RL_TITLE_LENGTH <= fw->title_length) { right_end = add; } } if (!has_mp) { return; } switch (just) { case JUST_LEFT: is_start = 1; /* fall through */ case JUST_RIGHT: if (td->has_an_upsidedown_rotation) { is_start = !is_start; } if (is_start) { if (td->has_an_upsidedown_rotation) { td->offset = max( td->offset, right_of_text + right_end + TBMP_MIN_RL_TITLE_LENGTH + TBMP_TITLE_PADDING); } else { td->offset = max( td->offset, left_of_text + left_end + TBMP_MIN_RL_TITLE_LENGTH + TBMP_TITLE_PADDING); } } else { if (td->has_an_upsidedown_rotation) { td->offset = min( td->offset, fw->title_length - (td->length + left_of_text + left_end + TBMP_MIN_RL_TITLE_LENGTH + TBMP_TITLE_PADDING)); } else { td->offset = min( td->offset, fw->title_length - (td->length + right_of_text + right_end + TBMP_MIN_RL_TITLE_LENGTH + TBMP_TITLE_PADDING)); } } break; case JUST_CENTER: default: break; } under_offset = td->offset - (under_width - td->length)/2; before_space = under_offset; if (td->has_vt) { after_space = td->layout.title_g.height - before_space - under_width; } else { after_space = td->layout.title_g.width - before_space - under_width; } if (td->has_an_upsidedown_rotation) { td->left_end_length = right_end; td->left_of_text_length = right_of_text; td->right_of_text_length = left_of_text; td->right_end_length = left_end; tmpi = before_space; before_space = after_space; after_space = tmpi; } else { td->left_end_length = left_end; td->left_of_text_length = left_of_text; td->right_of_text_length = right_of_text; td->right_end_length = right_end; } if (td->has_vt) { td->under_text_g.width = td->bar_g.width; td->under_text_g.height = under_width; td->under_text_g.x = 0; td->under_text_g.y = under_offset; } else { td->under_text_g.height = td->bar_g.height; td->under_text_g.width = under_width; td->under_text_g.x = under_offset; td->under_text_g.y = 0; } /* width & height */ if (td->has_vt) { /* left */ td->full_left_main_g.width = td->bar_g.width; td->full_left_main_g.height = before_space + td->left_buttons_g.height; td->left_main_g.width = td->bar_g.width; td->left_main_g.height = before_space; /* right */ td->full_right_main_g.width = td->bar_g.width; td->full_right_main_g.height = after_space + td->right_buttons_g.height; td->right_main_g.width = td->bar_g.width; td->right_main_g.height = after_space; } else { /* left */ td->full_left_main_g.height = td->bar_g.height; td->full_left_main_g.width = before_space + td->left_buttons_g.width; td->left_main_g.height = td->bar_g.height; td->left_main_g.width = before_space; /* right */ td->full_right_main_g.height = td->bar_g.height; td->full_right_main_g.width = after_space + td->right_buttons_g.width; td->right_main_g.height = td->bar_g.height; td->right_main_g.width = after_space; } /* position */ if (td->has_an_upsidedown_rotation) { td->full_right_main_g.x = td->bar_g.x; td->full_right_main_g.y = td->bar_g.y; td->right_main_g.x = 0; td->right_main_g.y = 0; } else { td->full_left_main_g.x = td->bar_g.x; td->full_left_main_g.y = td->bar_g.y; td->left_main_g.x = 0; td->left_main_g.y = 0; } if (td->has_vt) { if (td->has_an_upsidedown_rotation) { td->full_left_main_g.x = td->bar_g.x; td->full_left_main_g.y = td->full_right_main_g.height + td->bar_g.y + td->under_text_g.height; td->left_main_g.y = td->under_text_g.y + td->under_text_g.height; td->left_main_g.x = 0; } else { td->full_right_main_g.x = td->bar_g.x; td->full_right_main_g.y = td->full_left_main_g.height + td->bar_g.y + td->under_text_g.height; td->right_main_g.y = td->under_text_g.y + td->under_text_g.height; td->right_main_g.x = 0; } } else { if (td->has_an_upsidedown_rotation) { td->full_left_main_g.x = td->full_right_main_g.width + td->bar_g.x + td->under_text_g.width; td->full_left_main_g.y = td->bar_g.y; td->left_main_g.x = td->under_text_g.x + td->under_text_g.width; td->left_main_g.y = 0; } else { td->full_right_main_g.x = td->full_left_main_g.width + td->bar_g.x + td->under_text_g.width; td->full_right_main_g.y = td->bar_g.y; td->right_main_g.x = td->under_text_g.x + td->under_text_g.width; td->right_main_g.y = 0; } } } /* the returned geometries are relative to the titlebar (not the frame) */ static void 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) { int left_of_text = 0; int right_of_text = 0; int left_end = 0; int right_end = 0; left_of_text = border_mp_get_length( td, pm, acs, sf, TBMP_LEFT_OF_TEXT); left_end = border_mp_get_length( td, pm, acs, sf, TBMP_LEFT_END); right_of_text = border_mp_get_length( td, pm, acs, sf, TBMP_RIGHT_OF_TEXT); right_end = border_mp_get_length( td, pm, acs, sf, TBMP_RIGHT_END); if (left_of_text > 0 && left_of_text <= td->left_of_text_length) { if (td->has_vt) { left_of_text_g->y = td->under_text_g.y - left_of_text; left_of_text_g->x = 0; left_of_text_g->height = left_of_text; left_of_text_g->width = td->bar_g.width; } else { left_of_text_g->x = td->under_text_g.x - left_of_text; left_of_text_g->y = 0; left_of_text_g->width = left_of_text; left_of_text_g->height = td->bar_g.height; } } else { left_of_text_g->x = 0; left_of_text_g->y = 0; left_of_text_g->width = 0; left_of_text_g->height = 0; } if (right_of_text > 0 && right_of_text <= td->right_of_text_length) { if (td->has_vt) { right_of_text_g->y = td->under_text_g.y + td->under_text_g.height; right_of_text_g->x = 0; right_of_text_g->height = right_of_text; right_of_text_g->width = td->bar_g.width; } else { right_of_text_g->x = td->under_text_g.x + td->under_text_g.width; right_of_text_g->y = 0; right_of_text_g->width = right_of_text; right_of_text_g->height = td->bar_g.height; } } else { right_of_text_g->x = 0; right_of_text_g->y = 0; right_of_text_g->width = 0; right_of_text_g->height = 0; } if (left_end > 0 && left_end <= td->left_end_length) { if (td->has_vt) { left_end_g->y = 0; left_end_g->x = 0; left_end_g->height = left_end; left_end_g->width = td->bar_g.width; } else { left_end_g->x = 0; left_end_g->y = 0; left_end_g->width = left_end; left_end_g->height = td->bar_g.height; } } else { left_end_g->x = 0; left_end_g->y = 0; left_end_g->width = 0; left_end_g->height = 0; } if (right_end > 0 && right_end <= td->right_end_length) { if (td->has_vt) { right_end_g->y = td->layout.title_g.height - right_end; right_end_g->x = 0; right_end_g->height = right_end; right_end_g->width = td->bar_g.width; } else { right_end_g->x = td->layout.title_g.width - right_end; right_end_g->y = 0; right_end_g->width = right_end; right_end_g->height = td->bar_g.height; } } else { right_end_g->x = 0; right_end_g->y = 0; right_end_g->width = 0; right_end_g->height = 0; } return; } static Bool 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) { rectangle *tmp_g = NULL; Bool g_ok = True; if (is_left && TBMP_HAS_PART(TBMP_LEFT_BUTTONS, pm, acs, sf)) { *part = TBMP_LEFT_BUTTONS; tmp_g = &td->left_buttons_g; } else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_BUTTONS, pm, acs, sf)) { *part = TBMP_RIGHT_BUTTONS; tmp_g = &td->right_buttons_g; } else if (is_left && TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, sf)) { *part = TBMP_LEFT_MAIN; tmp_g = &td->full_left_main_g; } else if (!is_left && TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, sf)) { *part = TBMP_RIGHT_MAIN; tmp_g = &td->full_right_main_g; } else if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, sf)) { *part = TBMP_MAIN; tmp_g = &(td->bar_g); } else { *part = TBMP_NONE; } if (g && tmp_g) { g->x = tmp_g->x; g->y = tmp_g->y; g->width = tmp_g->width; g->height = tmp_g->height; g_ok = True; } return g_ok; } /* Redraws multi-pixmap titlebar (tril@igs.net) */ static void border_mp_draw_mp_titlebar( FvwmWindow *fw, titlebar_descr *td, DecorFace *df, Pixmap dest_pix, Window w) { FvwmPicture **pm; FvwmAcs *acs; Pixel *pixels; unsigned short solid_flags; unsigned short stretch_flags; rectangle tmp_g, left_of_text_g,left_end_g,right_of_text_g,right_end_g; dynamic_common_decorations *dcd; ButtonState bs; dcd = &(td->cd->dynamic_cd); bs = td->tbstate.tstate; pm = df->u.mp.pixmaps; acs = df->u.mp.acs; pixels = df->u.mp.pixels; stretch_flags = df->u.mp.stretch_flags; solid_flags = df->u.mp.solid_flags; tmp_g.x = 0; tmp_g.y = 0; tmp_g.width = td->layout.title_g.width; tmp_g.height = td->layout.title_g.height; if (TBMP_HAS_PART(TBMP_MAIN, pm, acs, solid_flags)) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_MAIN, dest_pix, w, &td->bar_g, &td->layout.title_g, bs, &tmp_g); } else if (td->length <= 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_LEFT_MAIN, dest_pix, w, NULL, &td->layout.title_g, bs, &tmp_g); } border_mp_get_extreme_geometry( td, pm, acs, solid_flags, &left_of_text_g, &right_of_text_g, &left_end_g, &right_end_g); if (td->length > 0) { if (TBMP_HAS_PART(TBMP_LEFT_MAIN, pm, acs, solid_flags) && td->left_main_g.width > 0 && td->left_main_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_LEFT_MAIN, dest_pix, w, &td->full_left_main_g, &td->layout.title_g, bs, &td->left_main_g); } if (TBMP_HAS_PART(TBMP_RIGHT_MAIN, pm, acs, solid_flags) && td->right_main_g.width > 0 && td->right_main_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_RIGHT_MAIN, dest_pix, w, &td->full_right_main_g, &td->layout.title_g, bs, &td->right_main_g); } if (TBMP_HAS_PART(TBMP_UNDER_TEXT, pm, acs, solid_flags) && td->under_text_g.width > 0 && td->under_text_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_UNDER_TEXT, dest_pix, w, NULL, &td->layout.title_g, bs, &td->under_text_g); } if (left_of_text_g.width > 0 && left_of_text_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_LEFT_OF_TEXT, dest_pix, w, NULL, &td->layout.title_g, bs, &left_of_text_g); } if (right_of_text_g.width > 0 && right_of_text_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_RIGHT_OF_TEXT, dest_pix, w, NULL, &td->layout.title_g, bs, &right_of_text_g); } } if (left_end_g.width > 0 && left_end_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_LEFT_END, dest_pix, w, NULL, &td->layout.title_g, bs, &left_end_g); } if (right_end_g.width > 0 && right_end_g.height > 0) { border_mp_render_into_pixmap( td, td->cd, pm, acs, pixels, solid_flags, stretch_flags, TBMP_RIGHT_END, dest_pix, w, NULL, &td->layout.title_g, bs, &right_end_g); } return; } /* * * draw title bar and buttons * */ static void 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) { register DecorFaceType type = DFS_FACE_TYPE(df->style); pixmap_background_type bg; rectangle dest_g; FvwmPicture *p; int width,height; int border; int lr_just, tb_just; common_decorations_type *cd; cd = td->cd; /* setup some default */ bg.pixmap.fra.mask = 0; bg.pixmap.flags.is_stretched = 0; bg.pixmap.flags.is_tiled = 0; bg.flags.use_pixmap = 0; bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; if (DFS_BUTTON_RELIEF(df->style) == DFS_BUTTON_IS_FLAT) { border = 0; } else { border = HAS_MWM_BORDER(fw) ? 1 : 2; } dest_g.width = w_g->width; dest_g.height = w_g->height; dest_g.x = border; dest_g.y = border; switch (type) { case SimpleButton: /* do nothing */ break; case SolidButton: /* overwrite with the default background */ dest_g.x = 0; dest_g.y = 0; border_fill_pixmap_background(dest_pix, &dest_g, solid_bg, cd); break; case VectorButton: case DefaultVectorButton: border_draw_vector_to_pixmap( dest_pix, cd, is_toggled, &df->u.vector, w_g); break; case MiniIconButton: case PixmapButton: case ShrunkPixmapButton: case StretchedPixmapButton: if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0) { break; } if (FMiniIconsSupported && type == MiniIconButton) { if (!fw->mini_icon) { break; } p = fw->mini_icon; if (cd->cs >= 0) { bg.pixmap.fra.mask |= FRAM_HAVE_ICON_CSET; bg.pixmap.fra.colorset = &Colorset[cd->cs]; } } else { p = df->u.p; } width = p->width; height = p->height; if ((type == ShrunkPixmapButton || type == MiniIconButton) && (p->width > w_g->width - 2*border || p->height > w_g->height - 2*border)) { /* do so that the picture fit into the destination */ bg.pixmap.stretch_w = width = min(w_g->width - 2*border, p->width); bg.pixmap.stretch_h = height = min(w_g->height - 2*border, p->height); bg.pixmap.flags.is_stretched = 1; } else if (type == StretchedPixmapButton && (p->width < w_g->width - 2*border || p->height < w_g->height - 2*border)) { /* do so that the picture fit into the destination */ bg.pixmap.stretch_w = width = max(w_g->width - 2*border, p->width); bg.pixmap.stretch_h = height = max(w_g->height - 2*border, p->height); bg.pixmap.flags.is_stretched = 1; } lr_just = DFS_H_JUSTIFICATION(df->style); tb_just = DFS_V_JUSTIFICATION(df->style); if (!td->td_is_rotated && fw->title_text_rotation != ROTATION_0) { if (fw->title_text_rotation == ROTATION_180) { switch (lr_just) { case JUST_LEFT: lr_just = JUST_RIGHT; break; case JUST_RIGHT: lr_just = JUST_LEFT; break; case JUST_CENTER: default: break; } switch (tb_just) { case JUST_TOP: tb_just = JUST_BOTTOM; break; case JUST_BOTTOM: tb_just = JUST_TOP; break; case JUST_CENTER: default: break; } } else if (fw->title_text_rotation == ROTATION_90) { switch (lr_just) { case JUST_LEFT: tb_just = JUST_TOP; break; case JUST_RIGHT: tb_just = JUST_BOTTOM; break; case JUST_CENTER: default: tb_just = JUST_CENTER; break; } switch (DFS_V_JUSTIFICATION(df->style)) { case JUST_TOP: lr_just = JUST_RIGHT; break; case JUST_BOTTOM: lr_just = JUST_LEFT; break; case JUST_CENTER: default: lr_just = JUST_CENTER; break; } } else if (fw->title_text_rotation == ROTATION_270) { switch (lr_just) { case JUST_LEFT: tb_just = JUST_BOTTOM; break; case JUST_RIGHT: tb_just = JUST_TOP; break; case JUST_CENTER: default: tb_just = JUST_CENTER; break; } switch (DFS_V_JUSTIFICATION(df->style)) { case JUST_TOP: lr_just = JUST_LEFT; break; case JUST_BOTTOM: lr_just = JUST_RIGHT; break; case JUST_CENTER: default: lr_just = JUST_CENTER; break; } } } switch (lr_just) { case JUST_LEFT: dest_g.x = border; break; case JUST_RIGHT: dest_g.x = (int)(w_g->width - width - border); break; case JUST_CENTER: default: /* round down */ dest_g.x = (int)(w_g->width - width) / 2; break; } switch (tb_just) { case JUST_TOP: dest_g.y = border; break; case JUST_BOTTOM: dest_g.y = (int)(w_g->height - height - border); break; case JUST_CENTER: default: /* round down */ dest_g.y = (int)(w_g->height - height) / 2; break; } if (dest_g.x < border) { dest_g.x = border; } if (dest_g.y < border) { dest_g.y = border; } bg.flags.use_pixmap = 1; bg.pixmap.p = p->picture; bg.pixmap.shape = p->mask; bg.pixmap.alpha = p->alpha; bg.pixmap.depth = p->depth; bg.pixmap.g.width = p->width; bg.pixmap.g.height = p->height; border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd); break; case TiledPixmapButton: case AdjustedPixmapButton: if (w_g->width - 2*border <= 0 || w_g->height - 2*border <= 0) { break; } p = df->u.p; if (type == TiledPixmapButton) { bg.pixmap.flags.is_tiled = 1; } else { bg.pixmap.stretch_w = width = w_g->width - 2*dest_g.x; bg.pixmap.stretch_h = height = w_g->height - 2*dest_g.y; bg.pixmap.flags.is_stretched = 1; } bg.flags.use_pixmap = 1; bg.pixmap.p = p->picture; bg.pixmap.shape = p->mask; bg.pixmap.alpha = p->alpha; bg.pixmap.depth = p->depth; bg.pixmap.g.width = p->width; bg.pixmap.g.height = p->height; border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd); break; case MultiPixmap: /* for UseTitleStyle only */ { int is_left = left1right0; int part = TBMP_NONE; int ap, cs; unsigned int stretch; Pixmap tmp = None; FvwmPicture *full_pic = NULL; rectangle g; dynamic_common_decorations *dcd = &(cd->dynamic_cd); FvwmPicture **pm; FvwmAcs *acs; Pixel *pixels; unsigned short sf; pm = df->u.mp.pixmaps; acs = df->u.mp.acs; pixels = df->u.mp.pixels; sf = df->u.mp.solid_flags; if (!border_mp_get_use_title_style_parts_and_geometry( td, pm, acs, sf, is_left, &g, &part)) { g.width = 0; g.height = 0; g.x = 0; g.y = 0; } if (part == TBMP_NONE) { break; } if (sf & (1 << part)) { bg.flags.use_pixmap = 0; bg.pixel = pixels[part]; border_fill_pixmap_background( dest_pix, &dest_g, &bg, cd); break; } cs = acs[part].cs; ap = acs[part].alpha_percent; if (CSET_IS_TRANSPARENT_PR(cs)) { break; } if (cs >= 0) { bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA; bg.pixmap.fra.added_alpha_percent = ap; } stretch = !!(df->u.mp.stretch_flags & (1 << part)); bg.flags.use_pixmap = 1; dest_g.x = 0; dest_g.y = 0; if (cs >= 0 && use_title_style && g.width > 0 && g.height > 0 && !CSET_IS_TRANSPARENT_ROOT(cs) && (bg.pixmap.p = border_get_bar_pixmaps( dcd, &g, bs, cs, NULL, part, stretch, NULL)) != None) { bg.pixmap.g.width = g.width; bg.pixmap.g.height = g.height; bg.pixmap.flags.is_tiled = 1; bg.pixmap.g.x = w_g->x - g.x; bg.pixmap.g.y = w_g->y - g.y; bg.pixmap.shape = None; bg.pixmap.alpha = None; bg.pixmap.depth = Pdepth; } else if (CSET_IS_TRANSPARENT_ROOT(cs)) { tmp = border_create_root_transparent_pixmap( td, w, w_g->width, w_g->height, cs); bg.pixmap.p = tmp; bg.pixmap.g.width = w_g->width; bg.pixmap.g.height = w_g->height; bg.pixmap.shape = None; bg.pixmap.alpha = None; bg.pixmap.depth = Pdepth; } else if (cs >= 0) { int bg_w, bg_h; tmp = CreateBackgroundPixmap( dpy, w, w_g->width, w_g->height, &Colorset[cs], Pdepth, Scr.BordersGC, False); bg.pixmap.p = tmp; GetWindowBackgroundPixmapSize( &Colorset[cs], w_g->width, w_g->height, &bg_w, &bg_h); bg.pixmap.g.width = bg_w; bg.pixmap.g.height = bg_h; bg.pixmap.shape = None; bg.pixmap.alpha = None; bg.pixmap.depth = Pdepth; bg.pixmap.flags.is_tiled = 1; } else if (pm[part] && g.width > 0 && g.height > 0 && border_get_bar_pixmaps( dcd, &g, bs, -1, pm[part], part, stretch, &full_pic) != None && full_pic) { bg.pixmap.p = full_pic->picture; bg.pixmap.shape = full_pic->mask; bg.pixmap.alpha = full_pic->alpha; bg.pixmap.depth = full_pic->depth; bg.pixmap.g.width = full_pic->width; bg.pixmap.g.height = full_pic->height; bg.pixmap.g.x = w_g->x - g.x; bg.pixmap.g.y = w_g->y - g.y; } else if (pm[part]) { p = pm[part]; if (df->u.mp.stretch_flags & (1 << part)) { bg.pixmap.flags.is_stretched = 1; } else { bg.pixmap.flags.is_tiled = 1; } bg.pixmap.p = p->picture; bg.pixmap.shape = p->mask; bg.pixmap.alpha = p->alpha; bg.pixmap.depth = p->depth; bg.pixmap.g.width = p->width; bg.pixmap.g.height = p->height; bg.pixmap.stretch_w = dest_g.width - dest_g.x; bg.pixmap.stretch_h = dest_g.height - dest_g.y; } else { /* should not happen */ return; } if (bg.pixmap.p != None) { border_fill_pixmap_background( dest_pix, &dest_g, &bg, cd); } if (tmp != None) { XFreePixmap(dpy, tmp); } break; } case ColorsetButton: { colorset_t *cs_t = &Colorset[df->u.acs.cs]; int cs = df->u.acs.cs; Pixmap tmp = None; int bg_w, bg_h; if (CSET_IS_TRANSPARENT_PR(cs)) { break; } dest_g.x = 0; dest_g.y = 0; if (use_title_style && !CSET_IS_TRANSPARENT_ROOT(cs) && (bg.pixmap.p = border_get_bar_pixmaps( &(cd->dynamic_cd), &(td->bar_g), bs, cs, NULL, TBMP_NONE, 0, NULL)) != None) { bg.pixmap.g.width = td->bar_g.width; bg.pixmap.g.height = td->bar_g.height; bg.pixmap.g.x = w_g->x - td->bar_g.x; bg.pixmap.g.y = w_g->y - td->bar_g.y; } else if (CSET_IS_TRANSPARENT_ROOT(cs)) { tmp = border_create_root_transparent_pixmap( td, w, w_g->width, w_g->height, cs); if (tmp == None) { break; } bg.pixmap.p = tmp; bg.pixmap.g.width = w_g->width; bg.pixmap.g.height = w_g->height; bg.pixmap.shape = None; bg.pixmap.alpha = None; bg.pixmap.depth = Pdepth; } else { tmp = CreateBackgroundPixmap( dpy, w, w_g->width, w_g->height, cs_t, Pdepth, Scr.BordersGC, False); if (tmp == None) { break; } bg.pixmap.p = tmp; GetWindowBackgroundPixmapSize( cs_t, w_g->width, w_g->height, &bg_w, &bg_h); bg.pixmap.g.width = bg_w; bg.pixmap.g.height = bg_h; bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; } bg.flags.use_pixmap = 1; bg.pixmap.shape = None; bg.pixmap.alpha = None; bg.pixmap.depth = Pdepth; bg.pixmap.flags.is_tiled = 1; bg.pixmap.fra.mask = FRAM_HAVE_ADDED_ALPHA; bg.pixmap.fra.added_alpha_percent = df->u.acs.alpha_percent; border_fill_pixmap_background(dest_pix, &dest_g, &bg, cd); if (tmp) { XFreePixmap(dpy, tmp); } break; } case GradientButton: /* draw the gradient into the pixmap */ CreateGradientPixmap( dpy, dest_pix, Scr.TransMaskGC, df->u.grad.gradient_type, 0, 0, df->u.grad.npixels, df->u.grad.xcs, df->u.grad.do_dither, &df->u.grad.d_pixels, &df->u.grad.d_npixels, dest_pix, 0, 0, w_g->width, w_g->height, NULL); break; default: fvwm_msg(ERR, "DrawButton", "unknown button type: %i", type); break; } return; } static void border_set_button_pixmap( FvwmWindow *fw, titlebar_descr *td, int button, Pixmap *dest_pix, Window w) { pixmap_background_type bg; unsigned int mask; int is_left_button; int do_reverse_relief; ButtonState bs; DecorFace *df; rectangle *button_g; GC rgc; GC sgc; Bool free_bg_pixmap = False; rectangle pix_g; /* prepare variables */ mask = (1 << button); if (td->has_an_upsidedown_rotation) { is_left_button = (button & 1); } else { is_left_button = !(button & 1); } button_g = &td->layout.button_g[button]; bs = td->tbstate.bstate[button]; df = &TB_STATE(GetDecor(fw, buttons[button]))[bs]; rgc = td->cd->relief_gc; sgc = td->cd->shadow_gc; /* prepare background, either from the window colour or from the * border style */ if (!DFS_USE_BORDER_STYLE(df->style)) { /* fill with the button background colour */ bg.flags.use_pixmap = 0; bg.pixel = td->cd->back_color; pix_g.x = 0; pix_g.y = 0; pix_g.width = button_g->width; pix_g.height = button_g->height; border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd); } else { /* draw pixmap background inherited from border style */ rectangle relative_g; relative_g.width = td->frame_g.width; relative_g.height = td->frame_g.height; relative_g.x = button_g->x; relative_g.y = button_g->y; border_get_border_background( &bg, td->cd, button_g, &relative_g, &free_bg_pixmap, w); bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; /* set the geometry for drawing the Tiled pixmap; * FIXME: maybe add the relief as offset? */ pix_g.x = 0; pix_g.y = 0; pix_g.width = button_g->width; pix_g.height = button_g->height; border_fill_pixmap_background(*dest_pix, &pix_g, &bg, td->cd); if (free_bg_pixmap && bg.pixmap.p) { XFreePixmap(dpy, bg.pixmap.p); } } /* handle title style */ if (DFS_USE_TITLE_STYLE(df->style)) { /* draw background inherited from title style */ DecorFace *tsdf; Pixmap tmp; if (td->draw_rotation != ROTATION_0) { tmp = CreateRotatedPixmap( dpy, *dest_pix, td->layout.button_g[button].width, td->layout.button_g[button].height, Pdepth, Scr.BordersGC, td->restore_rotation); XFreePixmap(dpy, *dest_pix); *dest_pix = tmp; border_rotate_titlebar_descr(fw, td); button_g = &td->layout.button_g[button]; is_left_button = !(button & 1); } for (tsdf = &TB_STATE(GetDecor(fw, titlebar))[bs]; tsdf != NULL; tsdf = tsdf->next) { bg.pixel = tsdf->u.back; border_draw_decor_to_pixmap( fw, *dest_pix, w, &bg, button_g, tsdf, td, bs, True, (td->tbstate.toggled_bmask & mask), is_left_button); } if (td->draw_rotation != ROTATION_0) { tmp = CreateRotatedPixmap( dpy, *dest_pix, td->layout.button_g[button].width, td->layout.button_g[button].height, Pdepth, Scr.BordersGC, td->draw_rotation); XFreePixmap(dpy, *dest_pix); *dest_pix = tmp; border_rotate_titlebar_descr(fw, td); button_g = &td->layout.button_g[button]; if (td->has_an_upsidedown_rotation) { is_left_button = (button & 1); } else { is_left_button = !(button & 1); } } } /* handle button style */ for ( ; df; df = df->next) { /* draw background from button style */ bg.pixel = df->u.back; border_draw_decor_to_pixmap( fw, *dest_pix, w, &bg, button_g, df, td, bs, False, (td->tbstate.toggled_bmask & mask), is_left_button); } /* draw the button relief */ do_reverse_relief = !!(td->tbstate.pressed_bmask & mask); switch (DFS_BUTTON_RELIEF( TB_STATE(GetDecor(fw, buttons[button]))[bs].style)) { case DFS_BUTTON_IS_SUNK: do_reverse_relief ^= 1; /* fall through*/ case DFS_BUTTON_IS_UP: do_relieve_rectangle( dpy, *dest_pix, 0, 0, button_g->width - 1, button_g->height - 1, (do_reverse_relief) ? sgc : rgc, (do_reverse_relief) ? rgc : sgc, td->cd->relief_width, True); break; default: /* flat */ break; } return; } static void border_draw_one_button( FvwmWindow *fw, titlebar_descr *td, int button) { Pixmap p; /* make a pixmap */ if (td->layout.button_g[button].x < 0 || td->layout.button_g[button].y < 0) { return; } p = border_create_decor_pixmap(td->cd, &(td->layout.button_g[button])); /* set the background tile */ border_set_button_pixmap(fw, td, button, &p, FW_W_BUTTON(fw, button)); /* apply the pixmap and destroy it */ border_set_part_background(FW_W_BUTTON(fw, button), p); XFreePixmap(dpy, p); if ((td->tbstate.clear_bmask & (1 << button)) != 0) { XClearWindow(dpy, FW_W_BUTTON(fw, button)); } return; } static void border_draw_title_stick_lines( FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd, Pixmap dest_pix) { int i; int num; int min; int max; int left_x; int left_w; int right_x; int right_w; int under_text_length = 0; int under_text_offset = 0; int right_length = 0; int left_length = 0; rotation_t rotation; if (!( (HAS_STICKY_STIPPLED_TITLE(fw) && (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw))) || HAS_STIPPLED_TITLE(fw))) { return; } if (td->td_is_rotated) { rotation = td->restore_rotation; } else { rotation = ROTATION_0; } if (td->has_vt && td->under_text_g.height > 0) { under_text_length = td->under_text_g.height; under_text_offset = td->under_text_g.y; left_length = td->left_main_g.height - td->left_of_text_length - td->left_end_length; right_length = td->right_main_g.height - td->right_of_text_length - td->right_end_length; } else if (!td->has_vt && td->under_text_g.width > 0) { under_text_length = td->under_text_g.width; under_text_offset = td->under_text_g.x; left_length = td->left_main_g.width - td->left_of_text_length - td->left_end_length; right_length = td->right_main_g.width - td->right_of_text_length - td->right_end_length; } /* If the window is sticky either across pages or * desks and it has a stippled title, but nothing for * sticky_stippled_title, then don't bother drawing them, just * return immediately. -- Thomas Adam */ if ( (IS_STICKY_ACROSS_PAGES(fw) || IS_STICKY_ACROSS_DESKS(fw)) && (!HAS_STICKY_STIPPLED_TITLE(fw) && HAS_STIPPLED_TITLE(fw)) ) { return; } num = (int)(fw->title_thickness / WINDOW_TITLE_STICK_VERT_DIST / 2) * 2 - 1; min = fw->title_thickness / 2 - num * 2 + 1; max = fw->title_thickness / 2 + num * 2 - WINDOW_TITLE_STICK_VERT_DIST + 1; left_x = WINDOW_TITLE_STICK_OFFSET + td->left_end_length; left_w = ((under_text_length == 0)? td->offset:under_text_offset) - left_x - WINDOW_TITLE_TO_STICK_GAP - td->left_of_text_length; right_x = ((under_text_length == 0)? td->offset + td->length : under_text_offset + under_text_length) + td->right_of_text_length + WINDOW_TITLE_TO_STICK_GAP - 1; right_w = fw->title_length - right_x - WINDOW_TITLE_STICK_OFFSET - td->right_end_length; /* an odd number of lines every WINDOW_TITLE_STICK_VERT_DIST pixels */ if (left_w < WINDOW_TITLE_STICK_MIN_WIDTH) { left_x = td->left_end_length + ((left_length > WINDOW_TITLE_STICK_MIN_WIDTH)? (left_length - WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0); left_w = WINDOW_TITLE_STICK_MIN_WIDTH; } if (right_w < WINDOW_TITLE_STICK_MIN_WIDTH) { right_w = WINDOW_TITLE_STICK_MIN_WIDTH; right_x = fw->title_length - WINDOW_TITLE_STICK_MIN_WIDTH - 1 - td->right_end_length - ((right_length > WINDOW_TITLE_STICK_MIN_WIDTH)? (right_length - WINDOW_TITLE_STICK_MIN_WIDTH)/2 : 0); } for (i = min; i <= max; i += WINDOW_TITLE_STICK_VERT_DIST) { if (left_w > 0) { do_relieve_rectangle_with_rotation( dpy, dest_pix, SWAP_ARGS(td->has_vt, left_x, i), SWAP_ARGS(td->has_vt, left_w, 1), tdd->sgc, tdd->rgc, 1, False, rotation); } if (right_w > 0) { do_relieve_rectangle_with_rotation( dpy, dest_pix, SWAP_ARGS(td->has_vt, right_x, i), SWAP_ARGS(td->has_vt, right_w, 1), tdd->sgc, tdd->rgc, 1, False, rotation); } } return; } static void border_draw_title_mono( FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd, FlocaleWinString *fstr, Pixmap dest_pix) { int has_vt; has_vt = HAS_VERTICAL_TITLE(fw); XFillRectangle( dpy, dest_pix, td->cd->relief_gc, td->offset - 2, 0, td->length+4, fw->title_thickness); if (fw->visible_name != (char *)NULL) { FlocaleDrawString(dpy, fw->title_font, fstr, 0); } /* for mono, we clear an area in the title bar where the window * title goes, so that its more legible. For color, no need */ do_relieve_rectangle( dpy, dest_pix, 0, 0, SWAP_ARGS(has_vt, td->offset - 3, fw->title_thickness - 1), tdd->rgc, tdd->sgc, td->cd->relief_width, False); do_relieve_rectangle( dpy, dest_pix, SWAP_ARGS(has_vt, td->offset + td->length + 2, 0), SWAP_ARGS(has_vt, fw->title_length - td->length - td->offset - 3, fw->title_thickness - 1), tdd->rgc, tdd->sgc, td->cd->relief_width, False); XDrawLine( dpy, dest_pix, tdd->sgc, SWAP_ARGS(has_vt, 0, td->offset + td->length + 1), SWAP_ARGS(has_vt, td->offset + td->length + 1, fw->title_thickness)); return; } static void border_draw_title_relief( FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd, Pixmap dest_pix) { int reverse = 0; rotation_t rotation; if (td->td_is_rotated) { rotation = td->restore_rotation; } else { rotation = ROTATION_0; } /* draw title relief */ switch (DFS_BUTTON_RELIEF(*tdd->tstyle)) { case DFS_BUTTON_IS_SUNK: reverse = 1; case DFS_BUTTON_IS_UP: do_relieve_rectangle_with_rotation( dpy, dest_pix, 0, 0, SWAP_ARGS( td->has_vt, fw->title_length - 1, fw->title_thickness - 1), (reverse) ? tdd->sgc : tdd->rgc, (reverse) ? tdd->rgc : tdd->sgc, td->cd->relief_width, True, rotation); break; default: /* flat */ break; } return; } static void border_draw_title_deep( FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd, FlocaleWinString *fstr, Pixmap dest_pix, Window w) { DecorFace *df; pixmap_background_type bg; bg.flags.use_pixmap = 0; for (df = tdd->df; df != NULL; df = df->next) { if (df->style.face_type == MultiPixmap) { border_mp_draw_mp_titlebar( fw, td, df, dest_pix, w); } else { bg.pixel = df->u.back; border_draw_decor_to_pixmap( fw, dest_pix, w, &bg, &td->layout.title_g, df, td, td->tbstate.tstate, True, tdd->is_toggled, 1); } } FlocaleDrawString(dpy, fw->title_font, &tdd->fstr, 0); return; } static void border_get_titlebar_draw_descr( FvwmWindow *fw, titlebar_descr *td, title_draw_descr *tdd, Pixmap dest_pix) { rectangle *title_g; memset(tdd, 0, sizeof(*tdd)); /* prepare the gcs and variables */ if (td->tbstate.is_title_pressed) { tdd->rgc = td->cd->shadow_gc; tdd->sgc = td->cd->relief_gc; } else { tdd->rgc = td->cd->relief_gc; tdd->sgc = td->cd->shadow_gc; } NewFontAndColor(fw->title_font, td->cd->fore_color, td->cd->back_color); title_g = &td->layout.title_g; tdd->tstyle = &TB_STATE( GetDecor(fw, titlebar))[td->tbstate.tstate].style; tdd->df = &TB_STATE(GetDecor(fw, titlebar))[td->tbstate.tstate]; /* fetch the title string */ tdd->fstr.str = fw->visible_name; tdd->fstr.win = dest_pix; if (td->td_is_rotated) { tdd->fstr.flags.text_rotation = ROTATION_0; } else { tdd->fstr.flags.text_rotation = fw->title_text_rotation; } if (td->has_vt) { tdd->fstr.y = td->offset; tdd->fstr.x = fw->title_text_offset + 1; } else { tdd->fstr.x = td->offset; tdd->fstr.y = fw->title_text_offset + 1; } if (td->cd->cs >= 0) { tdd->fstr.colorset = &Colorset[td->cd->cs]; tdd->fstr.flags.has_colorset = 1; } tdd->fstr.gc = Scr.TitleGC; return; } static void border_set_title_pixmap( FvwmWindow *fw, titlebar_descr *td, Pixmap *dest_pix, Window w) { pixmap_background_type bg; title_draw_descr tdd; FlocaleWinString fstr; Bool free_bg_pixmap = False; rectangle pix_g; border_get_titlebar_draw_descr(fw, td, &tdd, *dest_pix); /* prepare background, either from the window colour or from the * border style */ if (!DFS_USE_BORDER_STYLE(*tdd.tstyle)) { /* fill with the button background colour */ bg.flags.use_pixmap = 0; bg.pixel = td->cd->back_color; pix_g.x = 0; pix_g.y = 0; pix_g.width = td->layout.title_g.width; pix_g.height = td->layout.title_g.height; border_fill_pixmap_background( *dest_pix, &pix_g, &bg, td->cd); } else { /* draw pixmap background inherited from border style */ rectangle relative_g; Pixmap tmp; if (td->draw_rotation != ROTATION_0) { tmp = CreateRotatedPixmap( dpy, *dest_pix, td->layout.title_g.width, td->layout.title_g.height, Pdepth, Scr.BordersGC, td->restore_rotation); XFreePixmap(dpy, *dest_pix); *dest_pix = tmp; border_rotate_titlebar_descr(fw, td); } relative_g.width = td->frame_g.width; relative_g.height = td->frame_g.height; relative_g.x = td->layout.title_g.x; relative_g.y = td->layout.title_g.y; border_get_border_background( &bg, td->cd, &td->layout.title_g, &relative_g, &free_bg_pixmap, w); bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; /* set the geometry for drawing the Tiled pixmap; * FIXME: maybe add the relief as offset? */ pix_g.x = 0; pix_g.y = 0; pix_g.width = td->layout.title_g.width; pix_g.height = td->layout.title_g.height; border_fill_pixmap_background( *dest_pix, &pix_g, &bg, td->cd); if (free_bg_pixmap && bg.pixmap.p) { XFreePixmap(dpy, bg.pixmap.p); } if (td->draw_rotation != ROTATION_0) { tmp = CreateRotatedPixmap( dpy, *dest_pix, td->layout.title_g.width, td->layout.title_g.height, Pdepth, Scr.BordersGC, td->draw_rotation); XFreePixmap(dpy, *dest_pix); *dest_pix = tmp; border_rotate_titlebar_descr(fw, td); } } if (Pdepth < 2) { border_draw_title_mono(fw, td, &tdd, &fstr, *dest_pix); } else { border_draw_title_deep(fw, td, &tdd, &fstr, *dest_pix, w); } border_draw_title_relief(fw, td, &tdd, *dest_pix); border_draw_title_stick_lines(fw, td, &tdd, *dest_pix); return; } static void border_draw_title( FvwmWindow *fw, titlebar_descr *td) { Pixmap p; if (td->layout.title_g.x < 0 || td->layout.title_g.y < 0) { return; } if (td->draw_rotation != ROTATION_0) { border_rotate_titlebar_descr(fw, td); } /* make a pixmap */ p = border_create_decor_pixmap(td->cd, &(td->layout.title_g)); /* set the background tile */ #if 0 fprintf(stderr,"drawing title\n"); #endif border_set_title_pixmap(fw, td, &p, FW_W_TITLE(fw)); if (td->draw_rotation != ROTATION_0) { Pixmap tmp; tmp = CreateRotatedPixmap( dpy, p, td->layout.title_g.width, td->layout.title_g.height, Pdepth, Scr.BordersGC, td->draw_rotation); XFreePixmap(dpy, p); p = tmp; border_rotate_titlebar_descr(fw, td); } /* apply the pixmap and destroy it */ border_set_part_background(FW_W_TITLE(fw), p); XFreePixmap(dpy, p); if (td->tbstate.do_clear_title) { XClearWindow(dpy, FW_W_TITLE(fw)); } return; } static void border_draw_buttons( FvwmWindow *fw, titlebar_descr *td) { int i; /* draw everything in a big loop */ #if 0 fprintf(stderr, "drawing buttons 0x%04x\n", td->tbstate.draw_bmask); #endif for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { unsigned int mask = (1 << i); if ((td->tbstate.draw_bmask & mask) != 0) { border_draw_one_button(fw, td, i); } } /* update the button states */ fw->decor_state.buttons_drawn |= td->tbstate.draw_bmask; fw->decor_state.buttons_inverted = td->tbstate.pressed_bmask; fw->decor_state.buttons_lit = td->tbstate.lit_bmask; fw->decor_state.buttons_toggled = td->tbstate.toggled_bmask; return; } static void border_setup_use_title_style( FvwmWindow *fw, titlebar_descr *td) { int i; DecorFace *df, *tsdf; ButtonState bs, tsbs; /* use a full bar pixmap (for Colorset) or non window size pixmaps * (for MultiPixmap) under certain condition: * - for the buttons which use title style * - for title which have a button with UseTitle style */ tsbs = td->tbstate.tstate; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { bs = td->tbstate.bstate[i]; df = &TB_STATE(GetDecor(fw, buttons[i]))[bs]; tsdf = &TB_STATE(GetDecor(fw, buttons[i]))[tsbs]; if (FW_W_BUTTON(fw, i) != None) { if (DFS_USE_TITLE_STYLE(df->style)) { border_setup_bar_pixmaps( td, &(td->cd->dynamic_cd), &TB_STATE(GetDecor(fw, titlebar))[bs], bs); } if (DFS_USE_TITLE_STYLE(tsdf->style)) { border_setup_bar_pixmaps( td, &(td->cd->dynamic_cd), &TB_STATE(GetDecor(fw, titlebar))[tsbs], tsbs); } } } return; } static void border_rotate_titlebar_descr( FvwmWindow *fw, titlebar_descr *td) { rotation_t rotation; int i, tmpi; static titlebar_descr saved_td; if (td->draw_rotation == ROTATION_0) { return; } if (!td->has_been_saved) { td->has_been_saved = True; memcpy(&saved_td, td, sizeof(titlebar_descr)); } if (!td->td_is_rotated) { /* make the bar horizontal */ switch(td->draw_rotation) { case ROTATION_90: /* cw */ rotation = ROTATION_270; break; case ROTATION_270: /* ccw */ rotation = ROTATION_90; break; case ROTATION_180: rotation = ROTATION_180; break; default: return; } td->has_vt = 0; td->has_an_upsidedown_rotation = 0; td->td_is_rotated = 1; } else { /* restore */ memcpy(td, &saved_td, sizeof(titlebar_descr)); td->td_is_rotated = 0; return; } #define ROTATE_RECTANGLE(rot, r, vs_frame, vs_titlebar, vs_title) \ { \ rectangle tr; \ tr.x = r->x; \ tr.y = r->y; \ tr.width = r->width; \ tr.height = r->height; \ switch(rot) \ { \ case ROTATION_270: /* ccw */ \ tr.x = r->y; \ if (vs_frame) \ { \ tr.y = td->frame_g.width - (r->x+r->width); \ } \ else if (vs_titlebar) \ { \ tr.y = td->bar_g.width - \ (r->x+r->width); \ } \ else if (vs_title) \ { \ tr.y = td->layout.title_g.width - \ (r->x+r->width); \ } \ else \ { \ tr.y = r->x; \ } \ tr.width = r->height; \ tr.height = r->width; \ break; \ case ROTATION_90: /* cw */ \ if (vs_frame) \ { \ tr.x = td->frame_g.height - (r->y+r->height); \ } \ else if (vs_titlebar) \ { \ tr.x = td->bar_g.height - \ (r->y+r->height); \ } \ else if (vs_title) \ { \ tr.x = td->layout.title_g.height - \ (r->y+r->height); \ } \ else \ { \ tr.x = r->y; \ } \ tr.y = r->x; \ tr.width = r->height; \ tr.height = r->width; \ break; \ case ROTATION_180: \ if (vs_frame) \ { \ tr.x = td->frame_g.width - (r->x+r->width); \ } \ else if (vs_titlebar) \ { \ tr.x = td->bar_g.width - \ (r->x + r->width); \ } \ else if (vs_title) \ { \ tr.x = td->layout.title_g.width - \ (r->x + r->width); \ } \ else \ { \ tr.x = r->x; \ } \ break; \ case ROTATION_0: \ break; \ } \ r->x = tr.x; \ r->y = tr.y; \ r->width = tr.width; \ r->height = tr.height; \ } switch(rotation) { case ROTATION_90: td->offset = td->layout.title_g.height - td->offset - td->length; tmpi = td->left_end_length; td->left_end_length = td->right_end_length; td->right_end_length = tmpi; tmpi = td->left_of_text_length; td->left_of_text_length = td->right_of_text_length; td->right_of_text_length = tmpi; break; case ROTATION_270: break; case ROTATION_180: td->offset = td->layout.title_g.width - td->offset - td->length; tmpi = td->left_end_length; td->left_end_length = td->right_end_length; td->right_end_length = tmpi; tmpi = td->left_of_text_length; td->left_of_text_length = td->right_of_text_length; td->right_of_text_length = tmpi; break; case ROTATION_0: break; } ROTATE_RECTANGLE(rotation, (&td->left_buttons_g), True, False, False) ROTATE_RECTANGLE(rotation, (&td->right_buttons_g), True, False, False) for (i=0; i < NUMBER_OF_TITLE_BUTTONS; i++) { ROTATE_RECTANGLE( rotation, (&td->layout.button_g[i]), True, False, False) } ROTATE_RECTANGLE(rotation, (&td->under_text_g), False, False, True) ROTATE_RECTANGLE(rotation, (&td->left_main_g), False, False, True) ROTATE_RECTANGLE(rotation, (&td->right_main_g), False, False, True) ROTATE_RECTANGLE(rotation, (&td->full_left_main_g), True, False, False) ROTATE_RECTANGLE(rotation, (&td->full_right_main_g), True, False, False) ROTATE_RECTANGLE(rotation, (&td->layout.title_g), True, False, False) ROTATE_RECTANGLE(rotation, (&td->bar_g), True, False, False) ROTATE_RECTANGLE(rotation, (&td->frame_g), False, False, False); #undef ROTATE_RECTANGLE } static void 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) { int i; if ((pressed_parts & PART_BUTTONS) != PART_NONE && pressed_button >= 0) { tbstate->pressed_bmask = (1 << pressed_button); } else { tbstate->pressed_bmask = 0; } if ((clear_parts & CLEAR_BUTTONS) != CLEAR_NONE) { tbstate->clear_bmask = ~0; } else { tbstate->clear_bmask = 0; } tbstate->lit_bmask = (do_hilight == True) ? ~0 : 0; if ((pressed_parts & PART_TITLE) != PART_NONE) { tbstate->is_title_pressed = 1; } else { tbstate->is_title_pressed = 0; } if ((clear_parts & CLEAR_TITLE) != CLEAR_NONE) { tbstate->do_clear_title = 1; } else { tbstate->do_clear_title = 0; } tbstate->is_title_lit = (do_hilight == True) ? 1 : 0; tbstate->toggled_bmask = 0; for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { unsigned int mask = (1 << i); if (is_button_toggled(fw, i)) { tbstate->toggled_bmask |= mask; } tbstate->bstate[i] = border_flags_to_button_state( tbstate->pressed_bmask & mask, tbstate->lit_bmask & mask, tbstate->toggled_bmask & mask); } tbstate->tstate = border_flags_to_button_state( tbstate->is_title_pressed, tbstate->is_title_lit, 0); } static window_parts 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) { window_parts draw_parts; int i; DecorFace *df; int is_start = 0; JustificationType just; int lbl = 0; int rbl = 0; ret_td->cd = cd; ret_td->frame_g = *new_g; if (old_g == NULL) { old_g = &fw->g.frame; } frame_get_titlebar_dimensions(fw, old_g, NULL, &ret_td->old_layout); frame_get_titlebar_dimensions(fw, new_g, NULL, &ret_td->layout); ret_td->has_vt = HAS_VERTICAL_TITLE(fw); if (USE_TITLE_DECOR_ROTATION(fw)) { ret_td->draw_rotation = fw->title_text_rotation; switch(ret_td->draw_rotation) { case ROTATION_90: ret_td->restore_rotation = ROTATION_270; break; case ROTATION_270: /* ccw */ ret_td->restore_rotation = ROTATION_90; break; case ROTATION_180: ret_td->restore_rotation = ROTATION_180; break; default: break; } } if (fw->title_text_rotation == ROTATION_270 || fw->title_text_rotation == ROTATION_180) { ret_td->has_an_upsidedown_rotation = True; } /* geometry of the title bar title + buttons */ if (!ret_td->has_vt) { ret_td->bar_g.width = new_g->width - 2 * fw->boundary_width; ret_td->bar_g.height = ret_td->layout.title_g.height; ret_td->bar_g.x = fw->boundary_width; ret_td->bar_g.y = ret_td->layout.title_g.y; } else { ret_td->bar_g.width = ret_td->layout.title_g.width; ret_td->bar_g.height = new_g->height - 2 * fw->boundary_width; ret_td->bar_g.y = fw->boundary_width; ret_td->bar_g.x = ret_td->layout.title_g.x; } /* buttons geometries */ if (ret_td->has_vt) { ret_td->left_buttons_g.width = ret_td->bar_g.width; ret_td->right_buttons_g.width = ret_td->bar_g.width; } else { ret_td->left_buttons_g.height = ret_td->bar_g.height; ret_td->right_buttons_g.height = ret_td->bar_g.width; } for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (FW_W_BUTTON(fw, i) == None) { continue; } if (ret_td->has_vt) { if (i & 1) { rbl += ret_td->layout.button_g[i].height; } else { lbl += ret_td->layout.button_g[i].height; } } else { if (i & 1) { rbl += ret_td->layout.button_g[i].width; } else { lbl += ret_td->layout.button_g[i].width; } } } if (ret_td->has_an_upsidedown_rotation) { if (ret_td->has_vt) { ret_td->left_buttons_g.height = rbl; ret_td->right_buttons_g.height = lbl; ret_td->right_buttons_g.y = fw->boundary_width; ret_td->right_buttons_g.x = ret_td->bar_g.x; ret_td->left_buttons_g.y = ret_td->layout.title_g.y + ret_td->layout.title_g.height; ret_td->left_buttons_g.x = ret_td->bar_g.x; } else { ret_td->left_buttons_g.width = rbl; ret_td->right_buttons_g.width = lbl; ret_td->right_buttons_g.x = fw->boundary_width; ret_td->right_buttons_g.y = ret_td->bar_g.y; ret_td->left_buttons_g.x = ret_td->layout.title_g.x + ret_td->layout.title_g.width; ret_td->left_buttons_g.y = ret_td->bar_g.y; } } else { if (ret_td->has_vt) { ret_td->left_buttons_g.height = lbl; ret_td->right_buttons_g.height = rbl; ret_td->left_buttons_g.y = fw->boundary_width; ret_td->left_buttons_g.x = ret_td->bar_g.x; ret_td->right_buttons_g.y = ret_td->layout.title_g.y + ret_td->layout.title_g.height; ret_td->right_buttons_g.x = ret_td->bar_g.x; } else { ret_td->left_buttons_g.width = lbl; ret_td->right_buttons_g.width = rbl; ret_td->left_buttons_g.x = fw->boundary_width; ret_td->left_buttons_g.y = ret_td->bar_g.y; ret_td->right_buttons_g.x = ret_td->layout.title_g.x + ret_td->layout.title_g.width; ret_td->right_buttons_g.y = ret_td->bar_g.y; } } /* initialise flags */ border_get_titlebar_descr_state( fw, pressed_parts, pressed_button, clear_parts, do_hilight, &(ret_td->tbstate)); /* get the title string length and position * This is not in "tdd" (titlebar_draw_descr), because these are needed * to draw the buttons with UseTitleStyle */ just = TB_JUSTIFICATION(GetDecor(fw, titlebar)); if (fw->visible_name != (char *)NULL) { ret_td->length = FlocaleTextWidth( fw->title_font, fw->visible_name, (ret_td->has_vt) ? -strlen(fw->visible_name) : strlen(fw->visible_name)); if (ret_td->length > fw->title_length - 2*MIN_WINDOW_TITLE_TEXT_OFFSET) { ret_td->length = fw->title_length - 2*MIN_WINDOW_TITLE_TEXT_OFFSET; just = JUST_CENTER; } if (ret_td->length < 0) { ret_td->length = 0; } } else { ret_td->length = 0; } if (ret_td->length == 0) { just = JUST_CENTER; } df = &TB_STATE(GetDecor(fw, titlebar))[ret_td->tbstate.tstate]; switch (just) { case JUST_LEFT: is_start = 1; /* fall through */ case JUST_RIGHT: if (ret_td->has_an_upsidedown_rotation) { is_start = !is_start; } if (is_start) { if (WINDOW_TITLE_TEXT_OFFSET + ret_td->length <= fw->title_length) { ret_td->offset = WINDOW_TITLE_TEXT_OFFSET; } else { ret_td->offset = fw->title_length - ret_td->length; } } else { ret_td->offset = fw->title_length - ret_td->length - WINDOW_TITLE_TEXT_OFFSET; } break; case JUST_CENTER: default: ret_td->offset = (fw->title_length - ret_td->length) / 2; break; } if (ret_td->offset < MIN_WINDOW_TITLE_TEXT_OFFSET) { ret_td->offset = MIN_WINDOW_TITLE_TEXT_OFFSET; } /* setup MultiPixmap */ border_mp_get_titlebar_descr(fw, ret_td, df); /* determine the parts to draw */ draw_parts = border_get_tb_parts_to_draw( fw, ret_td, old_g, new_g, force_draw_parts); return draw_parts; } static void 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) { window_parts draw_parts; titlebar_descr td; if (!HAS_TITLE(fw)) { /* just reset border states */ fw->decor_state.parts_drawn &= ~(PART_TITLE); fw->decor_state.parts_lit &= ~(PART_TITLE); fw->decor_state.parts_inverted &= ~(PART_TITLE); fw->decor_state.buttons_drawn = 0; fw->decor_state.buttons_lit = 0; fw->decor_state.buttons_inverted = 0; fw->decor_state.buttons_toggled = 0; return; } memset(&td, 0, sizeof(td)); draw_parts = border_get_titlebar_descr( cd, fw, pressed_parts, pressed_button, force_draw_parts, clear_parts, old_g, new_g, do_hilight, &td); if ((draw_parts & PART_TITLE) != PART_NONE || (draw_parts & PART_BUTTONS) != PART_NONE) { /* set up UseTitleStyle Colorset */ border_setup_use_title_style(fw, &td); } if ((draw_parts & PART_TITLE) != PART_NONE) { border_draw_title(fw, &td); } if ((draw_parts & PART_BUTTONS) != PART_NONE) { border_draw_buttons(fw, &td); } border_free_bar_pixmaps(&(td.cd->dynamic_cd)); /* update the decor states */ fw->decor_state.parts_drawn |= draw_parts; if (do_hilight) { fw->decor_state.parts_lit |= draw_parts; } else { fw->decor_state.parts_lit &= ~draw_parts; } fw->decor_state.parts_inverted &= ~draw_parts; fw->decor_state.parts_inverted |= (draw_parts & pressed_parts); if (draw_parts & PART_BUTTONS) { fw->decor_state.buttons_drawn |= td.tbstate.draw_bmask; fw->decor_state.parts_lit = (do_hilight) ? ~0 : 0; if (td.tbstate.pressed_bmask) { fw->decor_state.buttons_inverted = td.tbstate.pressed_bmask; } else { fw->decor_state.buttons_inverted &= ~td.tbstate.draw_bmask; } fw->decor_state.buttons_toggled = (fw->decor_state.buttons_toggled & ~td.tbstate.max_bmask) | td.tbstate.toggled_bmask; } return; } /* * * Redraws the windows borders * */ static void 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) { border_relief_descr br; window_parts draw_parts; Bool do_clear; if (HAS_NO_BORDER(fw)) { /* just reset border states */ fw->decor_state.parts_drawn &= ~(PART_FRAME | PART_HANDLES); fw->decor_state.parts_lit &= ~(PART_FRAME | PART_HANDLES); fw->decor_state.parts_inverted &= ~(PART_FRAME | PART_HANDLES); return; } do_clear = (clear_parts & CLEAR_FRAME) ? True : False; /* determine the parts to draw and the position to place them */ if (HAS_DEPRESSABLE_BORDER(fw)) { pressed_parts &= PART_FRAME; } else { pressed_parts = PART_NONE; } force_draw_parts &= PART_FRAME; memset(&br, 0, sizeof(br)); draw_parts = border_get_parts_and_pos_to_draw( cd, fw, pressed_parts, force_draw_parts, old_g, new_g, do_hilight, &br); if ((draw_parts & PART_FRAME) != PART_NONE) { border_draw_all_border_parts( cd, fw, &br, new_g, draw_parts, pressed_parts, do_hilight, do_clear); } /* update the decor states */ fw->decor_state.parts_drawn |= draw_parts; if (do_hilight) { fw->decor_state.parts_lit |= draw_parts; } else { fw->decor_state.parts_lit &= ~draw_parts; } fw->decor_state.parts_inverted &= ~draw_parts; fw->decor_state.parts_inverted |= (draw_parts & pressed_parts); return; } /* ---------------------------- interface functions ------------------------ */ DecorFace *border_get_border_style( FvwmWindow *fw, Bool has_focus) { DecorFace *df; if (has_focus == True) { df = &(GetDecor(fw, BorderStyle.active)); } else { df = &(GetDecor(fw, BorderStyle.inactive)); } return df; } int border_is_using_border_style( FvwmWindow *fw, Bool has_focus) { ButtonState bs; int is_pressed; int is_toggled; int i; /* title */ is_pressed = (FW_W_TITLE(fw) == PressedW); bs = border_flags_to_button_state(is_pressed, has_focus, 0); if (DFS_USE_BORDER_STYLE(TB_STATE(GetDecor(fw, titlebar))[bs].style)) { return 1; } for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { if (FW_W_BUTTON(fw, i) == None) { continue; } is_pressed = (FW_W_BUTTON(fw, i) == PressedW); is_toggled = (is_button_toggled(fw, i) == True); bs = border_flags_to_button_state( is_pressed, (has_focus == True), is_toggled); if (DFS_USE_BORDER_STYLE( TB_STATE(GetDecor(fw, buttons[i]))[bs].style)) { return 1; } } return 0; } int border_context_to_parts( int context) { if (context == C_FRAME || context == C_SIDEBAR || context == (C_FRAME | C_SIDEBAR)) { return PART_FRAME; } else if (context == C_F_TOPLEFT) { return PART_BORDER_NW; } else if (context == C_F_TOPRIGHT) { return PART_BORDER_NE; } else if (context == C_F_BOTTOMLEFT) { return PART_BORDER_SW; } else if (context == C_F_BOTTOMRIGHT) { return PART_BORDER_SE; } else if (context == C_SB_LEFT) { return PART_BORDER_W; } else if (context == C_SB_RIGHT) { return PART_BORDER_E; } else if (context == C_SB_TOP) { return PART_BORDER_N; } else if (context == C_SB_BOTTOM) { return PART_BORDER_S; } else if (context == C_TITLE) { return PART_TITLE; } else if (context & (C_LALL | C_RALL)) { return PART_BUTTONS; } return PART_NONE; } void border_get_part_geometry( FvwmWindow *fw, window_parts part, rectangle *sidebar_g, rectangle *ret_g, Window *ret_w) { int bw; bw = fw->boundary_width; /* ret_g->x and ret->y is just an offset relatively to the w, * maybe we can take the relief in account? */ switch (part) { case PART_BORDER_N: ret_g->x = sidebar_g->x; ret_g->y = 0; *ret_w = FW_W_SIDE(fw, 0); break; case PART_BORDER_E: ret_g->x = 2 * sidebar_g->x + sidebar_g->width - bw; ret_g->y = sidebar_g->y; *ret_w = FW_W_SIDE(fw, 1); break; case PART_BORDER_S: ret_g->x = sidebar_g->x; ret_g->y = 2 * sidebar_g->y + sidebar_g->height - bw; *ret_w = FW_W_SIDE(fw, 2); break; case PART_BORDER_W: ret_g->x = 0; ret_g->y = sidebar_g->y; *ret_w = FW_W_SIDE(fw, 3); break; case PART_BORDER_NW: ret_g->x = 0; ret_g->y = 0; *ret_w = FW_W_CORNER(fw, 0); break; case PART_BORDER_NE: ret_g->x = sidebar_g->x + sidebar_g->width; ret_g->y = 0; *ret_w = FW_W_CORNER(fw, 1); break; case PART_BORDER_SW: ret_g->x = 0; ret_g->y = sidebar_g->y + sidebar_g->height; *ret_w = FW_W_CORNER(fw, 2); break; case PART_BORDER_SE: ret_g->x = sidebar_g->x + sidebar_g->width; ret_g->y = sidebar_g->y + sidebar_g->height; *ret_w = FW_W_CORNER(fw, 3); break; default: break; } switch (part) { case PART_BORDER_N: case PART_BORDER_S: ret_g->width = sidebar_g->width; ret_g->height = bw; break; case PART_BORDER_E: case PART_BORDER_W: ret_g->width = bw; ret_g->height = sidebar_g->height; break; case PART_BORDER_NW: case PART_BORDER_NE: case PART_BORDER_SW: case PART_BORDER_SE: ret_g->width = sidebar_g->x; ret_g->height = sidebar_g->y; break; default: return; } return; } int get_button_number(int context) { int i; for (i = 0; (C_L1 << i) & (C_LALL | C_RALL); i++) { if (context & (C_L1 << i)) { return i; } } return -1; } void 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) { common_decorations_type cd; Bool do_redraw_titlebar = False; window_parts pressed_parts; window_parts force_parts; int context; int item; if (fw == NULL) { return; } if (WAS_NEVER_DRAWN(fw)) { /* force drawing everything */ do_force = True; draw_parts = PART_ALL; SET_WAS_NEVER_DRAWN(fw, 0); } memset(&cd, 0, sizeof(cd)); /* can't compare with True here, old code calls this with value "2" */ if (do_force != False) { force_parts = draw_parts; } else { force_parts = PART_NONE; } if (has_focus) { /* don't re-draw just for kicks */ if (Scr.Hilite != fw && Scr.Hilite != NULL) { FvwmWindow *t = Scr.Hilite; Scr.Hilite = NULL; /* make sure that the previously highlighted * window got unhighlighted */ border_draw_decorations( t, PART_ALL, False, True, CLEAR_ALL, NULL, NULL); } Scr.Hilite = fw; } else if (fw == Scr.Hilite) { Scr.Hilite = NULL; } if (fw->Desk != Scr.CurrentDesk) { return; } if (IS_ICONIFIED(fw)) { DrawIconWindow(fw, True, True, True, False, NULL); return; } /* calculate some values and flags */ if ((draw_parts & PART_TITLEBAR) && HAS_TITLE(fw)) { do_redraw_titlebar = True; } get_common_decorations( &cd, fw, draw_parts, has_focus, False, do_redraw_titlebar); /* redraw */ context = frame_window_id_to_context(fw, PressedW, &item); if ((context & (C_LALL | C_RALL)) == 0) { item = -1; } pressed_parts = border_context_to_parts(context); if (new_g == NULL) { new_g = &fw->g.frame; } if (do_redraw_titlebar) { border_draw_titlebar( &cd, fw, pressed_parts & PART_TITLEBAR, item, force_parts & PART_TITLEBAR, clear_parts, old_g, new_g, has_focus); } if (draw_parts & PART_FRAME) { Pixmap save_pix = cd.dynamic_cd.frame_pixmap; memset(&cd, 0, sizeof(cd)); get_common_decorations( &cd, fw, draw_parts, has_focus, True, True); cd.dynamic_cd.frame_pixmap = save_pix; border_draw_border_parts( &cd, fw, (pressed_parts & (PART_FRAME | PART_HANDLES)), (force_parts & (PART_FRAME | PART_HANDLES)), clear_parts, old_g, new_g, has_focus); } if (cd.dynamic_cd.frame_pixmap != None) { XFreePixmap(dpy, cd.dynamic_cd.frame_pixmap); } return; } void border_undraw_decorations( FvwmWindow *fw) { memset(&fw->decor_state, 0, sizeof(fw->decor_state)); return; } /* * * redraw the decoration when style change * */ void border_redraw_decorations( FvwmWindow *fw) { FvwmWindow *u = Scr.Hilite; /* domivogt (6-Jun-2000): Don't check if the window is visible here. * If we do, some updates are not applied and when the window becomes * visible again, the X Server may not redraw the window. */ border_draw_decorations( fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL); Scr.Hilite = u; return; } /* * * get the the root transparent parts of the decoration * */ unsigned int border_get_transparent_decorations_part(FvwmWindow *fw) { DecorFace *df,*tdf; unsigned int draw_parts = PART_NONE; int i; window_parts pressed_parts; int context; int item; border_titlebar_state tbstate; Bool title_use_borderstyle = False; Bool buttons_use_borderstyle = False; Bool buttons_use_titlestyle = False; context = frame_window_id_to_context(fw, PressedW, &item); if ((context & (C_LALL | C_RALL)) == 0) { item = -1; } pressed_parts = border_context_to_parts(context); memset(&tbstate, 0, sizeof(tbstate)); border_get_titlebar_descr_state( fw, pressed_parts & PART_TITLEBAR, item, CLEAR_ALL, (Scr.Hilite == fw), &tbstate); for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++) { df = &TB_STATE(GetDecor(fw, buttons[i]))[tbstate.bstate[i]]; if (DFS_USE_TITLE_STYLE(df->style)) { buttons_use_titlestyle = True; } if (DFS_USE_BORDER_STYLE(df->style)) { buttons_use_borderstyle = True; } for(tdf = df; tdf != NULL; tdf = tdf->next) { if (DFS_FACE_TYPE(tdf->style) == ColorsetButton && CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs)) { draw_parts |= PART_BUTTONS; break; } } } df = &TB_STATE(GetDecor(fw, titlebar))[tbstate.tstate]; if (DFS_USE_BORDER_STYLE(df->style)) { title_use_borderstyle = True; } for(tdf = df; tdf != NULL; tdf = tdf->next) { if (DFS_FACE_TYPE(tdf->style) == ColorsetButton && CSET_IS_TRANSPARENT_ROOT(tdf->u.acs.cs)) { draw_parts |= PART_TITLE; break; } else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap) { int i; for (i = 0; i < TBMP_NUM_PIXMAPS; i++) { if (CSET_IS_TRANSPARENT_ROOT( tdf->u.mp.acs[i].cs)) { draw_parts |= PART_TITLE; break; } } } } df = border_get_border_style(fw, (Scr.Hilite == fw)); if (DFS_FACE_TYPE(df->style) == ColorsetButton && CSET_IS_TRANSPARENT_ROOT(df->u.acs.cs)) { draw_parts |= PART_FRAME|PART_HANDLES; } if (draw_parts & PART_FRAME) { if (title_use_borderstyle) { draw_parts |= PART_TITLE; } if (buttons_use_borderstyle) { draw_parts |= PART_BUTTONS; } } if ((draw_parts & PART_TITLE) && buttons_use_titlestyle) { draw_parts |= PART_BUTTONS; } #if 0 fprintf(stderr,"Transparant Part: %u\n", draw_parts); #endif return draw_parts; } /* ---------------------------- builtin commands --------------------------- */ /* * * Sets the allowed button states * */ void CMD_ButtonState(F_CMD_ARGS) { char *token; while ((token = PeekToken(action, &action))) { static char first = True; if (!token && first) { Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS; Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS; Scr.gs.use_inactive_down_buttons = DEFAULT_USE_INACTIVE_DOWN_BUTTONS; return; } first = False; if (StrEquals("activedown", token)) { Scr.gs.use_active_down_buttons = ParseToggleArgument( action, &action, DEFAULT_USE_ACTIVE_DOWN_BUTTONS, True); } else if (StrEquals("inactive", token)) { Scr.gs.use_inactive_buttons = ParseToggleArgument( action, &action, DEFAULT_USE_INACTIVE_BUTTONS, True); } else if (StrEquals("inactivedown", token)) { Scr.gs.use_inactive_down_buttons = ParseToggleArgument( action, &action, DEFAULT_USE_INACTIVE_DOWN_BUTTONS, True); } else { Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS; Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS; Scr.gs.use_inactive_down_buttons = DEFAULT_USE_INACTIVE_DOWN_BUTTONS; fvwm_msg(ERR, "cmd_button_state", "Unknown button state %s", token); return; } } return; } /* * * Sets the border style (veliaa@rpi.edu) * */ void CMD_BorderStyle(F_CMD_ARGS) { char *parm; char *prev; #ifdef USEDECOR FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor; #else FvwmDecor *decor = &Scr.DefaultDecor; #endif Scr.flags.do_need_window_update = 1; decor->flags.has_changed = 1; for (prev = action; (parm = PeekToken(action, &action)); prev = action) { if (StrEquals(parm, "active") || StrEquals(parm, "inactive")) { int len; char *end, *tmp; DecorFace tmpdf, *df; memset(&tmpdf.style, 0, sizeof(tmpdf.style)); DFS_FACE_TYPE(tmpdf.style) = SimpleButton; tmpdf.next = NULL; if (FMiniIconsSupported) { tmpdf.u.p = NULL; } if (StrEquals(parm,"active")) { df = &decor->BorderStyle.active; } else { df = &decor->BorderStyle.inactive; } df->flags.has_changed = 1; while (isspace(*action)) { ++action; } if (*action != '(') { if (!*action) { fvwm_msg( ERR, "SetBorderStyle", "error in %s border" " specification", parm); return; } while (isspace(*action)) { ++action; } if (ReadDecorFace(action, &tmpdf,-1,True)) { FreeDecorFace(dpy, df); *df = tmpdf; } break; } end = strchr(++action, ')'); if (!end) { fvwm_msg( ERR, "SetBorderStyle", "error in %s border specification", parm); return; } len = end - action + 1; tmp = safemalloc(len); strncpy(tmp, action, len - 1); tmp[len - 1] = 0; ReadDecorFace(tmp, df,-1,True); free(tmp); action = end + 1; } else if (strcmp(parm,"--")==0) { if (ReadDecorFace( prev, &decor->BorderStyle.active,-1,True)) { ReadDecorFace( prev, &decor->BorderStyle.inactive, -1, False); } decor->BorderStyle.active.flags.has_changed = 1; decor->BorderStyle.inactive.flags.has_changed = 1; break; } else { DecorFace tmpdf; memset(&tmpdf.style, 0, sizeof(tmpdf.style)); DFS_FACE_TYPE(tmpdf.style) = SimpleButton; tmpdf.next = NULL; if (FMiniIconsSupported) { tmpdf.u.p = NULL; } if (ReadDecorFace(prev, &tmpdf,-1,True)) { FreeDecorFace(dpy,&decor->BorderStyle.active); decor->BorderStyle.active = tmpdf; ReadDecorFace( prev, &decor->BorderStyle.inactive, -1, False); decor->BorderStyle.active.flags.has_changed = 1; decor->BorderStyle.inactive.flags.has_changed = 1; } break; } } return; }