From 31c22d65593a8293f77bb51bc9ed082a052723a0 Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Thu, 10 Nov 2022 19:50:15 -0700 Subject: [PATCH] Translucent Menus Adds new MenuStyle option 'Translucent', which can set the Translucent percent of menus using the associated style. This option takes one additional value that is a number between 0 (fully translucent) to 100 (not translucent). Supplying no value (or an invalid value), or using '!Translucent' turns translucency off. --- doc/fvwm3_manpage_source.adoc | 9 +- fvwm/menuroot.h | 3 + fvwm/menus.c | 193 ++++++++++++++++++++++++++++++---- fvwm/menustyle.c | 14 +++ fvwm/menustyle.h | 7 ++ libs/PictureGraphics.c | 4 +- libs/PictureGraphics.h | 4 + 7 files changed, 212 insertions(+), 22 deletions(-) diff --git a/doc/fvwm3_manpage_source.adoc b/doc/fvwm3_manpage_source.adoc index c6bded0f7..ac34f8e41 100644 --- a/doc/fvwm3_manpage_source.adoc +++ b/doc/fvwm3_manpage_source.adoc @@ -2523,7 +2523,8 @@ SubmenusLeft, SelectOnRelease, ItemFormat, VerticalItemSpacing, VerticalMargins, VerticalTitleSpacing, AutomaticHotkeys / !AutomaticHotkeys, UniqueHotkeyActivatesImmediate / !UniqueHotkeyActivatesImmediate, MouseWheel, ScrollOffPage / -!ScrollOffPage, TrianglesUseFore / !TrianglesUseFore. +!ScrollOffPage, TrianglesUseFore / !TrianglesUseFore, +Translucent / !Translucent. + In the above list some options are listed as option pairs or triples with a '/' in between. These options exclude each other. All paired @@ -2598,6 +2599,12 @@ style. No other parts of the colorset are used. _TitleColorset_ works exactly like _MenuColorset_, but is used only for menu titles. + +_Translucent_ controls a pseudo transparent effect that uses a image +of the desktop under the menu as its background image. This option +takes one value that is a number between 0 (fully translucent) +and 100 (not translucent), which is the percent of the translucency. +Use _!Translucent_ (or no additional value) to turn the effect off. ++ _Hilight3DThick_, _Hilight3DThin_ and _Hilight3DOff_ determine if the selected menu item is hilighted with a 3D relief. Thick reliefs are two pixels wide, thin reliefs are one pixel wide. diff --git a/fvwm/menuroot.h b/fvwm/menuroot.h index d0babf75a..ea092ab9b 100644 --- a/fvwm/menuroot.h +++ b/fvwm/menuroot.h @@ -147,6 +147,9 @@ typedef struct MenuRootDynamic int d_npixels; } stored_pixels; /* alloc pixels when dithering is used for gradients */ + /* x,y XMapRaise */ + int x; + int y; } MenuRootDynamic; /* access macros to dynamic menu members */ diff --git a/fvwm/menus.c b/fvwm/menus.c index 8bbea1c6b..160ce3555 100644 --- a/fvwm/menus.c +++ b/fvwm/menus.c @@ -77,6 +77,11 @@ #define SCTX_GET_MR(ctx) ((ctx).type == SCTX_MENU_ROOT ? \ (ctx).menu_root.menu_root : NULL) +#define MR_IS_TRANSLUCENT(mr) (!MR_IS_TEAR_OFF_MENU(mr) && \ + MST_IS_TRANSLUCENT(mr)) +#define MR_IS_TRANSPARENT(mr) (MR_IS_TRANSLUCENT(mr) || \ + CSET_IS_TRANSPARENT(MST_CSET_MENU((mr)))) + /* ---------------------------- imports ------------------------------------ */ /* This external is safe. It's written only during startup. */ @@ -219,6 +224,8 @@ typedef struct mloop_static_info_t } mloop_static_info_t; /* ---------------------------- forward declarations ----------------------- */ +static MenuRoot *seek_submenu_instance( + MenuRoot *parent_menu, MenuItem *parent_item); /* ---------------------------- local variables ---------------------------- */ @@ -380,11 +387,22 @@ static void animated_move_back( Bool transparent_bg = False; /* move it back */ - if (CSET_IS_TRANSPARENT(ST_CSET_MENU(MR_STYLE(mr)))) + if (MR_IS_TRANSPARENT(mr)) { transparent_bg = True; get_menu_repaint_transparent_parameters( &mrtp, mr, fw); + if (MR_IS_TRANSLUCENT(mr) && MR_SUBMENU_ITEM(mr)) + { + MenuRoot *smr; + smr = seek_submenu_instance( + mr, MR_SUBMENU_ITEM(mr)); + if (smr) + { + /* just unmap it here, popdown later */ + XUnmapWindow(dpy, MR_WINDOW(smr)); + } + } } end.x = start.x - MR_XANIMATION(mr); end.y = start.y; @@ -1908,6 +1926,7 @@ static void make_menu_window(MenuRoot *mr, Bool is_tear_off) /* Doh. Use the standard display instead. */ MR_CREATE_DPY(mr) = dpy; } + MR_IS_TEAR_OFF_MENU(mr) = 1; } else { @@ -2450,7 +2469,45 @@ static void paint_menu( } MR_IS_PAINTED(mr) = 1; /* paint the menu background */ - if (ms && MR_IS_BACKGROUND_SET(mr) == False) + if (MR_IS_TRANSLUCENT(mr)) + { + Pixmap trans = None; + FvwmRenderAttributes fra; + fra.mask = 0; + fra.mask = FRAM_HAVE_TINT; + fra.tint = Colorset[ST_CSET_MENU(ms)].bg; + fra.tint_percent = ST_TRANSLUCENT_PERCENT(ms); + + if (MR_IS_BACKGROUND_SET(mr) == False) + { + trans = PGraphicsCreateTranslucent( + dpy, MR_WINDOW(mr), &fra, + BACK_GC(ST_MENU_INACTIVE_GCS(ms)), + mr->d->x, mr->d->y, MR_WIDTH(mr), + MR_HEIGHT(mr)); + XMapRaised(dpy, MR_WINDOW(mr)); + if (trans != None) + { + XSetWindowBackgroundPixmap( + dpy, MR_WINDOW(mr), trans); + MR_IS_BACKGROUND_SET(mr) = True; + if (pevent == NULL) + { + XClearWindow(dpy, MR_WINDOW(mr)); + } else { + XClearArea( + dpy, MR_WINDOW(mr), + pevent->xexpose.x, + pevent->xexpose.y, + pevent->xexpose.width, + pevent->xexpose.height, + False); + } + XFreePixmap(dpy, trans); + } + } + } + else if (ms && MR_IS_BACKGROUND_SET(mr) == False) { SetWindowBackground( dpy, MR_WINDOW(mr), MR_WIDTH(mr), @@ -3078,8 +3135,7 @@ static int pop_menu_up( MR_HAS_POPPED_UP_RIGHT(mr) = 0; } MR_XANIMATION(parent_menu) += end_x - prev_x; - if (CSET_IS_TRANSPARENT(ST_CSET_MENU( - MR_STYLE(parent_menu)))) + if (MR_IS_TRANSPARENT(parent_menu)) { transparent_bg = True; get_menu_repaint_transparent_parameters( @@ -3262,10 +3318,21 @@ static int pop_menu_up( */ XMoveWindow(dpy, MR_WINDOW(mr), x, y); + mr->d->x = x; + mr->d->y = y; XSelectInput(dpy, MR_WINDOW(mr), event_mask); - XMapRaised(dpy, MR_WINDOW(mr)); - if (popdown_window) - XUnmapWindow(dpy, popdown_window); + if (MR_IS_TRANSLUCENT(mr)) + { + if (popdown_window) + XUnmapWindow(dpy, popdown_window); + paint_menu(mr, NULL, fw); + } + else + { + XMapRaised(dpy, MR_WINDOW(mr)); + if (popdown_window) + XUnmapWindow(dpy, popdown_window); + } XFlush(dpy); MR_MAPPED_COPIES(mr)++; MST_USAGE_COUNT(mr)++; @@ -5833,16 +5900,106 @@ void update_transparent_menu_bg( { last = True; } - if (!last && CSET_IS_TRANSPARENT_PR_TINT(ST_CSET_MENU(ms))) + if (!last && + (CSET_IS_TRANSPARENT_PR_TINT(ST_CSET_MENU(ms)) || + MR_IS_TRANSLUCENT(mr))) { /* too slow ... */ return; } - SetWindowBackgroundWithOffset( - dpy, MR_WINDOW(mr), step_x - current_x, step_y - current_y, - MR_WIDTH(mr), MR_HEIGHT(mr), - &Colorset[ST_CSET_MENU(ms)], Pdepth, - FORE_GC(MST_MENU_INACTIVE_GCS(mr)), False); + if (MR_IS_TRANSLUCENT(mr)) + { + Pixmap trans, tmp; + FvwmRenderAttributes fra; + fra.mask = 0; + fra.mask = FRAM_HAVE_TINT; + fra.tint = Colorset[ST_CSET_MENU(ms)].bg; + fra.tint_percent = ST_TRANSLUCENT_PERCENT(ms); + mr->d->x = step_x; + mr->d->y = step_y; + + if (current_x == step_x) + { + /* + * Reuse the old pixmap for the part of the menu + * that has not moved. (This can be extended to get + * two new rectangles, one in each direction) + * + * It saves the unmapping of the window and makes + * Things less flickering. + */ + GC my_gc; + unsigned long valuemask = GCSubwindowMode; + XGCValues values; + int out_y = (step_y < 0) ? -step_y : 0; + int delta_y = step_y - current_y; + values.subwindow_mode = IncludeInferiors; + trans = XCreatePixmap( + dpy, MR_WINDOW(mr), MR_WIDTH(mr), + MR_HEIGHT(mr), Pdepth); + my_gc = fvwmlib_XCreateGC(dpy, MR_WINDOW(mr), 0, NULL); + XChangeGC(dpy, my_gc, valuemask, &values); + XClearWindow(dpy, MR_WINDOW(mr)); + + if (current_y < step_y) + { + XCopyArea(dpy, MR_WINDOW(mr), trans, my_gc, 0, + delta_y, MR_WIDTH(mr), + MR_HEIGHT(mr) - delta_y, 0, 0); + tmp = PGraphicsCreateTranslucent( + dpy, MR_WINDOW(mr), &fra, + BACK_GC(ST_MENU_INACTIVE_GCS(ms)), + current_x, current_y + MR_HEIGHT(mr), + MR_WIDTH(mr), delta_y); + XCopyArea(dpy, tmp, trans, my_gc, 0, 0, + MR_WIDTH(mr), delta_y, + 0, MR_HEIGHT(mr) - delta_y); + } else { + XCopyArea(dpy, MR_WINDOW(mr), trans, my_gc, + 0, 0, MR_WIDTH(mr), + MR_HEIGHT(mr) + delta_y, + 0, -delta_y); + tmp = PGraphicsCreateTranslucent( + dpy, MR_WINDOW(mr), &fra, + BACK_GC(ST_MENU_INACTIVE_GCS(ms)), + current_x, step_y, MR_WIDTH(mr), + -delta_y); + XCopyArea(dpy, tmp, trans, my_gc, 0, 0, + MR_WIDTH(mr), -delta_y, 0, out_y); + } + XFreePixmap(dpy, tmp); + XFreeGC(dpy, my_gc); + } else { + XUnmapWindow(dpy, MR_WINDOW(mr)); + trans = PGraphicsCreateTranslucent( + dpy, MR_WINDOW(mr), &fra, + BACK_GC(ST_MENU_INACTIVE_GCS(ms)), + step_x, step_y, MR_WIDTH(mr), + MR_HEIGHT(mr)); + XMapRaised(dpy, MR_WINDOW(mr)); + } + XSetWindowBackgroundPixmap(dpy, MR_WINDOW(mr), trans); + XFreePixmap(dpy, trans); + if (current_x == step_x) + { + /* Redraw the border */ + 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)), + MST_BORDER_WIDTH(mr)); + } + } + else + { + SetWindowBackgroundWithOffset( + dpy, MR_WINDOW(mr), step_x - current_x, + step_y - current_y, MR_WIDTH(mr), MR_HEIGHT(mr), + &Colorset[ST_CSET_MENU(ms)], Pdepth, + FORE_GC(MST_MENU_INACTIVE_GCS(mr)), False); + } } @@ -5883,10 +6040,7 @@ void repaint_transparent_menu( } if (!is_bg_set) { - SetWindowBackground( - dpy, MR_WINDOW(mr), MR_WIDTH(mr), MR_HEIGHT(mr), - &Colorset[ST_CSET_MENU(ms)], Pdepth, - FORE_GC(MST_MENU_INACTIVE_GCS(mr)), False); + update_transparent_menu_bg(prtm, x, y, x, y, end_x, end_y); } /* redraw the background of non active item */ for (mi = MR_FIRST_ITEM(mr); mi != NULL; mi = MI_NEXT_ITEM(mi)) @@ -6522,7 +6676,10 @@ void UpdateMenuColorset(int cset) &Colorset[ST_CSET_MENU(ms2)], Pdepth, FORE_GC(MST_MENU_INACTIVE_GCS(mr)), - True); + False); + XClearArea( + dpy, MR_WINDOW(mr), 0, 0, + MR_WIDTH(mr), MR_HEIGHT(mr), True); } else if (ST_CSET_ACTIVE(ms2) == cset || ST_CSET_GREYED(ms2) == cset) diff --git a/fvwm/menustyle.c b/fvwm/menustyle.c index c14fe7735..47eda8ba2 100644 --- a/fvwm/menustyle.c +++ b/fvwm/menustyle.c @@ -134,6 +134,7 @@ static int menustyle_get_styleopt_index(char *option) "TitleFont", "VerticalMargins", "UniqueHotkeyActivatesImmediate", + "Translucent", NULL }; @@ -487,6 +488,7 @@ MenuStyle *menustyle_parse_style(F_CMD_ARGS) ST_SCROLL_OFF_PAGE(tmpms) = 1; ST_DO_HILIGHT_TITLE_BACK(tmpms) = 0; ST_USING_DEFAULT_TITLEFONT(tmpms) = True; + ST_TRANSLUCENT_PERCENT(tmpms) = 100; has_gc_changed = True; option = "fvwm"; } @@ -1072,6 +1074,18 @@ MenuStyle *menustyle_parse_style(F_CMD_ARGS) ST_HOTKEY_ACTIVATES_IMMEDIATE(tmpms) = on; break; + case 55: /* Translucent */ + if (!on || + GetIntegerArguments(args, NULL, val, 1) == 0 || + *val < 0 || *val > 100) + { + /* 100 percent means not translucent */ + ST_TRANSLUCENT_PERCENT(tmpms) = 100; + } else { + ST_TRANSLUCENT_PERCENT(tmpms) = *val; + } + break; + #if 0 case 99: /* PositionHints */ /* to be implemented */ diff --git a/fvwm/menustyle.h b/fvwm/menustyle.h index 13020af7a..f95481d0c 100644 --- a/fvwm/menustyle.h +++ b/fvwm/menustyle.h @@ -111,6 +111,12 @@ #define MST_PTITLEFONT(m) ((m)->s->ms->look.pTitleFont) #define ST_FONT_HEIGHT(s) ((s)->look.FontHeight) #define MST_FONT_HEIGHT(m) ((m)->s->ms->look.FontHeight) +#define ST_TRANSLUCENT_PERCENT(s) ((s)->look.TranslucentPercent) +#define MST_TRANSLUCENT_PERCENT(m) ((m)->s->ms->look.TranslucentPercent) +#define ST_IS_TRANSLUCENT(s) ((s)->look.TranslucentPercent != 100) +#define MST_IS_TRANSLUCENT(m) ((m)->s->ms->look.TranslucentPercent != 100) + + /* feel */ #define ST_IS_ANIMATED(s) ((s)->feel.flags.is_animated) #define MST_IS_ANIMATED(m) ((m)->s->ms->feel.flags.is_animated) @@ -268,6 +274,7 @@ typedef struct MenuLook FlocaleFont *pStdFont; FlocaleFont *pTitleFont; int FontHeight; + int TranslucentPercent; } MenuLook; typedef struct MenuStyle diff --git a/libs/PictureGraphics.c b/libs/PictureGraphics.c index 82c6e0c8d..98a711e9d 100644 --- a/libs/PictureGraphics.c +++ b/libs/PictureGraphics.c @@ -1361,7 +1361,7 @@ void PGraphicsTintRectangle( } } -#if 0 /* humm... maybe useful one day with menus */ +/* Used for translucent menus */ Pixmap PGraphicsCreateTranslucent( Display *dpy, Window win, FvwmRenderAttributes *fra, GC gc, int x, int y, int width, int height) @@ -1470,8 +1470,6 @@ Pixmap PGraphicsCreateTranslucent( } return r; } -#endif - /* never tested and used ! */ Pixmap PGraphicsCreateDitherPixmap( diff --git a/libs/PictureGraphics.h b/libs/PictureGraphics.h index d950c0d24..dcfb0d1fc 100644 --- a/libs/PictureGraphics.h +++ b/libs/PictureGraphics.h @@ -125,6 +125,10 @@ void PGraphicsTintRectangle( Drawable dest, Bool dest_is_a_window, GC gc, GC mono_gc, GC alpha_gc, int dest_x, int dest_y, int dest_w, int dest_h); +Pixmap PGraphicsCreateTranslucent( + Display *dpy, Window win, FvwmRenderAttributes *fra, GC gc, + int x, int y, int width, int height); + /* never used ! */ Pixmap PGraphicsCreateDitherPixmap( Display *dpy, Window win, Drawable src, Pixmap mask, int depth, GC gc,