Skip to content

Commit

Permalink
Translucent Menus
Browse files Browse the repository at this point in the history
  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.
  • Loading branch information
somiaj authored and ThomasAdam committed Nov 15, 2022
1 parent c0bc5fe commit ad8e4a0
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 27 deletions.
18 changes: 17 additions & 1 deletion doc/fvwm3_manpage_source.adoc
Expand Up @@ -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
Expand Down Expand Up @@ -2598,6 +2599,21 @@ 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.
The translucent effect only applies to normal menus and does not
apply to "torn off" menus. Note, only the menu background is
translucent, the _HilightBack_ of the active item and
_HilightTitleBack_ of the title are not. To have a fully translucent
menu use the following.
+
....
MenuStyle * Translucent 60, !HilightBack, !HilightTitleBack, ActiveFore
....
+
_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.
Expand Down
8 changes: 3 additions & 5 deletions fvwm/menuitem.c
Expand Up @@ -101,7 +101,7 @@ static void draw_highlight_background(
struct MenuPaintItemParameters *mpip, int x, int y, int width,
int height, colorset_t *cs, GC gc)
{
if (cs != NULL && cs->pixmap && cs->pixmap_type != PIXMAP_TILED)
if (cs->pixmap && cs->pixmap_type != PIXMAP_TILED)
{
Pixmap p;

Expand Down Expand Up @@ -484,8 +484,7 @@ void menuitem_paint(
y_offset + relief_thickness,
lit_x_end - lit_x_start,
y_height - relief_thickness,
(cs >= 0 ? &Colorset[cs] : NULL),
gcs.back_gc);
&Colorset[cs], gcs.back_gc);
item_cleared = True;
}
}
Expand Down Expand Up @@ -528,8 +527,7 @@ void menuitem_paint(
y_offset + relief_thickness,
lit_x_end - lit_x_start,
y_height - relief_thickness,
(cs >= 0 ? &Colorset[cs] : NULL),
gcs.back_gc);
&Colorset[cs], gcs.back_gc);
item_cleared = True;
}
}
Expand Down
3 changes: 3 additions & 0 deletions fvwm/menuroot.h
Expand Up @@ -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 */
Expand Down
192 changes: 174 additions & 18 deletions fvwm/menus.c
Expand Up @@ -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. */
Expand Down Expand Up @@ -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 ---------------------------- */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -2450,7 +2469,44 @@ 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 = 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),
Expand Down Expand Up @@ -3078,8 +3134,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(
Expand Down Expand Up @@ -3262,10 +3317,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)++;
Expand Down Expand Up @@ -5833,16 +5899,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);
}
}


Expand Down Expand Up @@ -5883,10 +6039,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))
Expand Down Expand Up @@ -6522,7 +6675,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)
Expand Down
14 changes: 14 additions & 0 deletions fvwm/menustyle.c
Expand Up @@ -134,6 +134,7 @@ static int menustyle_get_styleopt_index(char *option)
"TitleFont",
"VerticalMargins",
"UniqueHotkeyActivatesImmediate",
"Translucent",
NULL
};

Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -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 */
Expand Down
7 changes: 7 additions & 0 deletions fvwm/menustyle.h
Expand Up @@ -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)
Expand Down Expand Up @@ -268,6 +274,7 @@ typedef struct MenuLook
FlocaleFont *pStdFont;
FlocaleFont *pTitleFont;
int FontHeight;
int TranslucentPercent;
} MenuLook;

typedef struct MenuStyle
Expand Down

0 comments on commit ad8e4a0

Please sign in to comment.