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 committed Nov 12, 2022
1 parent 9a2e418 commit f7b773e
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 28 deletions.
9 changes: 8 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,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.
Expand Down
57 changes: 51 additions & 6 deletions fvwm/menuitem.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ static void draw_tear_off_bar(

static void draw_highlight_background(
struct MenuPaintItemParameters *mpip, int x, int y, int width,
int height, colorset_t *cs, GC gc)
int height, colorset_t *cs, GC gc, int tint_p)
{
if (cs != NULL && cs->pixmap && cs->pixmap_type != PIXMAP_TILED)
if (cs->pixmap && cs->pixmap_type != PIXMAP_TILED)
{
Pixmap p;

Expand Down Expand Up @@ -146,6 +146,51 @@ static void draw_highlight_background(
}
XFreePixmap(dpy, p);
}
#if 0
/* Make background translucent
* This currently isn't working, cannot correctly compute
* the rectangle to grab the screenshot from that gets sent
* to PGraphicsCreateTranslucent. The image is slightly off
* so need to find a way to correctly compute the x and y location
* of the highlighted rectangle.
*/
else if (tint_p < 100)
{
/* Make background translucent */
Pixmap trans = None;
FvwmRenderAttributes fra;
Window mr;
int mx, my, mh, mw, mb, md;

fra.mask = FRAM_HAVE_TINT;
fra.tint = cs->bg;
fra.tint_percent = tint_p;
XGetGeometry(dpy, mpip->w, &mr, &mx, &my, &mw, &mh, &mb, &md);
/* Error is here, mx, my = location of menu window, x, y = location
* inside of menu window, but there is some offset I cannot figure out.
*/
trans = PGraphicsCreateTranslucent(
dpy, mpip->w, &fra, gc, x + mx,
y + my, width, height);
if (trans != None)
{
XGCValues gcv;
int gcm;
GC bgc;
gcv.tile = trans;
gcv.fill_style = FillTiled;
gcm = GCFillStyle | GCTile;
bgc = fvwmlib_XCreateGC(dpy, mpip->w, gcm, &gcv);
XFillRectangle(dpy, mpip->w, bgc, x, y, width, height);
XFreeGC(dpy, bgc);
}
else
{
XFillRectangle(dpy, mpip->w, gc, x, y, width, height);
}
XFreePixmap(dpy, trans);
}
#endif
else
{
XFillRectangle(dpy, mpip->w, gc, x, y, width, height);
Expand Down Expand Up @@ -484,8 +529,8 @@ 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,
ST_TRANSLUCENT_PERCENT(ms));
item_cleared = True;
}
}
Expand Down Expand Up @@ -528,8 +573,8 @@ 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,
ST_TRANSLUCENT_PERCENT(ms));
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
Loading

0 comments on commit f7b773e

Please sign in to comment.