diff -U3 -r fvwm_patched/fvwm/borders.c fvwm/borders.c --- fvwm_patched/fvwm/borders.c 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/borders.c 2007-06-08 02:21:08.000000000 +0200 @@ -1654,6 +1654,7 @@ True : False; xgcv.fill_style = FillSolid; valuemask = GCFillStyle; + if (!bg->flags.use_pixmap) { /* solid pixel */ @@ -1846,13 +1847,26 @@ 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, window_parts part) + rectangle *part_g, rectangle *relative_g, int *free_bg_pixmap, Window w, window_parts part, FvwmPicture *fp) { *free_bg_pixmap = False; - if (cd->texture_pixmap) + if (fp) { bg->flags.use_pixmap = 1; + bg->pixmap.p = fp->picture; + bg->pixmap.g.width = fp->width; + bg->pixmap.g.height = fp->height; + bg->pixmap.shape = None; + bg->pixmap.alpha = None; + bg->pixmap.depth = fp->depth; + bg->pixmap.flags.is_tiled = 1; + bg->pixmap.flags.is_stretched = 0; + bg->pixmap.fra.mask = 0; + } + else 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; @@ -1947,6 +1961,18 @@ return; } +#define DRAWBORDER(PIX,X,Y,WIDTH,HEIGHT) \ + { \ + fp = df->u.mb.pixmaps[PIX]; \ + border_get_border_background( \ + &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w, PART_NONE, fp); \ + r.x = X; \ + r.y = Y; \ + r.width = WIDTH; \ + r.height = HEIGHT; \ + border_fill_pixmap_background(p, &r, &bg, cd); \ + } + 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, @@ -1959,6 +1985,7 @@ Pixmap p; Window w; Bool free_bg_pixmap = False; + int x, y, width, height; /* make a pixmap */ border_get_part_geometry(fw, part, sidebar_g, &part_g, &w); @@ -1972,8 +1999,28 @@ 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, part); + + DecorFace* df; + FvwmPicture* fp = 0; + df = border_get_border_style(fw, (Scr.Hilite == fw)); + if (DFS_FACE_TYPE(df->style) == MultiBorder) + { + int id = -1; + if (part==PART_BORDER_NW) id = 0; + if (part==PART_BORDER_N) id = 1; + if (part==PART_BORDER_NE) id = 2; + if (part==PART_BORDER_E) id = 3; + if (part==PART_BORDER_SE) id = 4; + if (part==PART_BORDER_S) id = 5; + if (part==PART_BORDER_SW) id = 6; + if (part==PART_BORDER_W) id = 7; + + if (id>=0 && df->u.mb.pixmaps[id]) + { + fp = df->u.mb.pixmaps[id]; + } + } + if (cd->texture_pixmap) { switch (part) @@ -2016,13 +2063,100 @@ 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); + + border_get_border_background( + &bg, cd, &part_g, &relative_g, &free_bg_pixmap, w, PART_NONE, fp); + + int px = bg.pixmap.g.x; + int py = bg.pixmap.g.y; + + if (fp) + { + /* Position pixmap so that it's aligned to the edge of the window */ + if (part & PART_BOTTOM) + { + bg.pixmap.g.y = fp->height - sidebar_g->y; + if (part == PART_BORDER_S) + { + bg.pixmap.g.y = fp->height - fw->boundary_width; + } + } + if (part & PART_RIGHT) + { + bg.pixmap.g.x = fp->width - sidebar_g->x; + if (part == PART_BORDER_E) + { + bg.pixmap.g.x = fp->width - fw->boundary_width; + } + } + } + + /* 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); + + bg.pixmap.g.x = px; + bg.pixmap.g.y = py; + + if (fp) + { + height = pix_g.height; + width = pix_g.width; + x = pix_g.x; + y = pix_g.y; + + /* draw parts from other borders that overflow because of their width/height */ + rectangle r; + if (part==PART_BORDER_S) + { + DRAWBORDER(6, pix_g.x - sidebar_g->x, fw->boundary_width - fp->height, fp->width - sidebar_g->x, height); + DRAWBORDER(4, pix_g.width - fp->width + sidebar_g->x, fw->boundary_width - fp->height, fp->width - sidebar_g->x, height); + } + if (!IS_SHADED(fw)) + { + if (part==PART_BORDER_E) + { + DRAWBORDER(2, fw->boundary_width - fp->width, pix_g.y - sidebar_g->y, width, fp->height - sidebar_g->y); + DRAWBORDER(4, fw->boundary_width - fp->width, pix_g.height - fp->height + sidebar_g->y, width, fp->height - sidebar_g->y); + } + if (part==PART_BORDER_W) + { + DRAWBORDER(0, x, pix_g.y - sidebar_g->y, width, fp->height - sidebar_g->y); + DRAWBORDER(6, x, pix_g.height - fp->height + sidebar_g->y, width, fp->height - sidebar_g->y); + } + } + if (part==PART_BORDER_N) + { + DRAWBORDER(2, pix_g.width - fp->width + sidebar_g->x, y, fp->width - sidebar_g->x, height); + DRAWBORDER(0, pix_g.x - fp->width + sidebar_g->x, y, fp->width - sidebar_g->x, height); + } + /* Use the top border for the whole height of the titlebar, overflowing to parts of the bottom corners if shaded */ + if (IS_SHADED(fw)) + { + if (part==PART_BORDER_W) + { + DRAWBORDER(0, 0, -height, width, height); + } + if (part==PART_BORDER_SW) + { + DRAWBORDER(0, 0, -height*2, width, height - fw->boundary_width); + } + if (part==PART_BORDER_E) + { + DRAWBORDER(2, fw->boundary_width - fp->width, -height, width, height); + } + if (part==PART_BORDER_SE) + { + DRAWBORDER(2, width - fp->width, -height*2, width, height - fw->boundary_width); + } + } + } + if (HAS_FLUXBOX_HANDLES(fw) && (part & PART_BOTTOM)) { pix_g.y = part_g.height - fw->boundary_width; @@ -2039,6 +2173,7 @@ border_fill_fluxbox_handle(p, &pix_g, cd, !(part & PART_BORDER_S)); } } + if (free_bg_pixmap && bg.pixmap.p) { XFreePixmap(dpy, bg.pixmap.p); @@ -2093,7 +2228,7 @@ do_clear); } } - + return; } @@ -3720,7 +3855,7 @@ 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, PART_NONE); + &bg, td->cd, button_g, &relative_g, &free_bg_pixmap, w, PART_NONE, (FvwmPicture *)NULL); bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; /* set the geometry for drawing the Tiled pixmap; @@ -4170,7 +4305,7 @@ 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, PART_NONE); + &free_bg_pixmap, w, PART_NONE, (FvwmPicture *)NULL); bg.pixmap.g.x = 0; bg.pixmap.g.y = 0; /* set the geometry for drawing the Tiled pixmap; diff -U3 -r fvwm_patched/fvwm/builtins.c fvwm/builtins.c --- fvwm_patched/fvwm/builtins.c 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/builtins.c 2007-06-08 01:42:49.000000000 +0200 @@ -784,6 +784,50 @@ return s; } +static char *ReadMultiBorderDecor(char *s, DecorFace *df) +{ + FvwmPictureAttributes fpa; + FvwmPicture **pm; + char *token; + int x; + int y; + + pm = df->u.mb.pixmaps; + df->style.face_type = MultiBorder; + + for (x = 0; x < 8; x++) + { + s = DoPeekToken(s, &token, " ", NULL, NULL); + if (s == NULL) + { + break; + } + if (pm[x]) + { + PDestroyFvwmPicture(dpy, pm[x]); + } + pm[x] = PCacheFvwmPicture(dpy, Scr.NoFocusWin, NULL, + token, fpa); + + if (!pm[x]) + { + fvwm_msg(ERR, "ReadMultiBorderDecor", + "Pixmap '%s' could not be loaded", + token); + for(y = 0; y < x; y++) + { + if (pm[y]) + { + PDestroyFvwmPicture(dpy, pm[y]); + } + } + return NULL; + } + } + + return s; +} + /* * * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor @@ -1493,6 +1537,14 @@ free(df->u.mp.pixels); } break; + case MultiBorder: + for (i = 0; i < 8; i++) + { + if (df->u.mb.pixmaps[i]) + { + PDestroyFvwmPicture(dpy, df->u.mb.pixmaps[i]); + } + } case VectorButton: case DefaultVectorButton: if (df->u.vector.x) @@ -1862,6 +1914,15 @@ return False; } } + else if (strncasecmp(style,"MultiBorder",11)==0) + { + s = ReadMultiBorderDecor(s, df); + if (!s) + { + return False; + } + DFS_FACE_TYPE(df->style) = MultiBorder; + } else if (FMiniIconsSupported && strncasecmp (style, "MiniIcon", 8) == 0) { diff -U3 -r fvwm_patched/fvwm/menus.c fvwm/menus.c --- fvwm_patched/fvwm/menus.c 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/menus.c 2007-06-08 01:42:49.000000000 +0200 @@ -2484,6 +2484,41 @@ return do_clear; } +#define DRAWMENUBORDER(NUM, XX, YY) XCopyArea(\ + dpy, pm[(NUM)]->picture, MR_WINDOW(mr), Scr.TransMaskGC,\ + 0, 0, pm[(NUM)]->width, pm[(NUM)]->height, (XX), (YY)) +static Bool paint_menu_multipixmap_background( + MenuRoot *mr, XEvent *pevent) +{ + MenuStyle *ms = MR_STYLE(mr); + int width, height, x, y; + int bw = MST_BORDER_WIDTH(mr); + FvwmPicture **pm; + pm = ST_FACE(ms).u.mb.pixmaps; + + width = MR_WIDTH(mr); + height = MR_HEIGHT(mr); + + FvwmPicture *p = pm[0]; + + width = MR_WIDTH(mr); + height = MR_HEIGHT(mr); + + x = 0; + + for (x = 0; x < width; x+=pm[1]->width) DRAWMENUBORDER(1, x, 0); + for (x = 0; x < width; x+=pm[5]->width) DRAWMENUBORDER(5, x, height-pm[5]->height); + for (x = 0; x < height; x+=pm[3]->height) DRAWMENUBORDER(3, width-pm[3]->height, x); + for (x = 0; x < height; x+=pm[7]->height) DRAWMENUBORDER(7, 0, x); + + DRAWMENUBORDER(0, 0, 0); + DRAWMENUBORDER(2, width-pm[2]->width, 0); + DRAWMENUBORDER(4, width-pm[4]->width, height-pm[4]->height); + DRAWMENUBORDER(6, 0, height-pm[6]->height); + + return False; +} + static Bool paint_menu_pixmap_background( MenuRoot *mr, XEvent *pevent) { @@ -2588,15 +2623,20 @@ { /* Only the border was obscured. Redraw it centrally instead of * redrawing several menu items. */ - RelieveRectangle( - dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1, - MR_HEIGHT(mr) - 1, (Pdepth < 2) ? - SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) : - HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)), - SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw); + if (ms && ST_FACE(ms).type == MultiPixmapMenu) { - return; + paint_menu_multipixmap_background(mr, pevent); } + else + { + RelieveRectangle( + dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1, + MR_HEIGHT(mr) - 1, (Pdepth < 2) ? + SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) : + HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)), + SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw); + } + return; } MR_IS_PAINTED(mr) = 1; /* paint the menu background */ @@ -2631,6 +2671,9 @@ case PixmapMenu: do_clear = paint_menu_pixmap_background(mr, pevent); break; + case MultiPixmapMenu: + do_clear = paint_menu_multipixmap_background(mr, pevent); + break; case TiledPixmapMenu: XSetWindowBackgroundPixmap( dpy, MR_WINDOW(mr), ST_FACE(ms).u.p->picture); @@ -2643,11 +2686,14 @@ } } /* if (ms) */ /* draw the relief */ - RelieveRectangle(dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1, - MR_HEIGHT(mr) - 1, (Pdepth < 2) ? - SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) : - HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)), - SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw); + if (!(ms && ST_FACE(ms).type == MultiPixmapMenu)) + { + RelieveRectangle(dpy, MR_WINDOW(mr), 0, 0, MR_WIDTH(mr) - 1, + MR_HEIGHT(mr) - 1, (Pdepth < 2) ? + SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)) : + HILIGHT_GC(MST_MENU_INACTIVE_GCS(mr)), + SHADOW_GC(MST_MENU_INACTIVE_GCS(mr)), bw); + } /* paint the menu items */ for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi)) { diff -U3 -r fvwm_patched/fvwm/menustyle.c fvwm/menustyle.c --- fvwm_patched/fvwm/menustyle.c 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/menustyle.c 2007-06-08 01:42:49.000000000 +0200 @@ -156,6 +156,8 @@ char *token; char *action = s; FvwmPictureAttributes fpa; + FvwmPicture **pm; + int x, y; s = GetNextToken(s, &style); if (style && strncasecmp(style, "--", 2) == 0) @@ -267,6 +269,58 @@ return False; } } + else if (StrEquals(style,"MultiBorder")) + { + fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; + pm = mf->u.mb.pixmaps; + + for (x = 0; x < 8; x++) + { + if (pm[x]) + { + PDestroyFvwmPicture(dpy, pm[x]); + } + s = GetNextToken(s, &token); + if (token) + { + pm[x] = PCacheFvwmPicture(dpy, Scr.NoFocusWin, NULL, token, fpa); + if (!pm[x]) + { + fvwm_msg(ERR, + "menustyle_parse_face", "Pixmap '%s' could not be loaded", + token); + } + } + else + { + fvwm_msg(ERR, + "menustyle_parse_face", "Too few parameters for MultiBorder"); + } + if (!token || !pm[x]) + { + for (y = 0; y < x; y++) + { + if (pm[y]) + { + PDestroyFvwmPicture(dpy, pm[y]); + pm[y] = 0; + } + } + free(style); + if (token) + { + free(token); + } + if (mf->type == MultiPixmapMenu) + { + mf->type = SimpleMenu; + } + return False; + } + mf->type = MultiPixmapMenu; + free(token); + } + } else { if (verbose) diff -U3 -r fvwm_patched/fvwm/menustyle.h fvwm/menustyle.h --- fvwm_patched/fvwm/menustyle.h 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/menustyle.h 2007-06-08 01:42:49.000000000 +0200 @@ -189,6 +189,7 @@ GradientMenu, PixmapMenu, TiledPixmapMenu, + MultiPixmapMenu, SolidMenu /* max button is 8 (0x8) */ } MenuFaceType; @@ -238,6 +239,9 @@ { union { + struct { + FvwmPicture *pixmaps[8]; + } mb; FvwmPicture *p; Pixel back; struct diff -U3 -r fvwm_patched/fvwm/screen.h fvwm/screen.h --- fvwm_patched/fvwm/screen.h 2007-06-08 01:33:06.000000000 +0200 +++ fvwm/screen.h 2007-06-08 01:42:49.000000000 +0200 @@ -99,6 +99,7 @@ AdjustedPixmapButton, ShrunkPixmapButton, MultiPixmap, + MultiBorder, MiniIconButton, SolidButton, ColorsetButton @@ -158,6 +159,9 @@ Pixel *pixels; unsigned short solid_flags; } mp; + struct { + FvwmPicture *pixmaps[8]; + } mb; struct { int cs;