Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translucent Menus #760

Merged
merged 1 commit into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion doc/fvwm3_manpage_source.adoc
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading