diff --unified --recursive --text fvwm-2.6.9/fvwm/borders.c fvwm-patched/fvwm/borders.c
--- fvwm-2.6.9/fvwm/borders.c	2020-08-21 16:16:28.114047517 -0600
+++ fvwm-patched/fvwm/borders.c	2020-08-21 16:34:52.530676541 -0600
@@ -58,6 +58,7 @@
 /* ---------------------------- imports ------------------------------------ */
 
 extern Window PressedW;
+extern Window HoverW;
 
 /* ---------------------------- included code files ------------------------ */
 
@@ -235,6 +236,7 @@
 	unsigned clear_bmask : NUMBER_OF_TITLE_BUTTONS;
 	unsigned draw_bmask : NUMBER_OF_TITLE_BUTTONS;
 	unsigned max_bmask : NUMBER_OF_TITLE_BUTTONS;
+	unsigned hover_bmask : NUMBER_OF_TITLE_BUTTONS;
 	ButtonState bstate[NUMBER_OF_TITLE_BUTTONS];
 	unsigned is_title_pressed : 1;
 	unsigned is_title_lit : 1;
@@ -340,8 +342,12 @@
 
 /* rules to get button state */
 static ButtonState border_flags_to_button_state(
-	int is_pressed, int is_lit, int is_toggled)
+	int is_pressed, int is_lit, int is_toggled, int is_hover)
 {
+	if (is_lit && is_hover && Scr.gs.use_hover_buttons)
+	{
+		return BS_ActiveHover;
+	}
 	if (!is_lit && Scr.gs.use_inactive_buttons)
 	{
 		if (is_pressed && Scr.gs.use_inactive_down_buttons)
@@ -862,7 +868,7 @@
 	/* check if state changed */
 	old_state = border_flags_to_button_state(
 		(fw->decor_state.parts_inverted & PART_TITLE),
-		(fw->decor_state.parts_lit & PART_TITLE), 0);
+		(fw->decor_state.parts_lit & PART_TITLE), 0, 0);
 	if (old_state != td->tbstate.tstate)
 	{
 		draw_parts |= PART_TITLE;
@@ -886,7 +892,8 @@
 		old_state = border_flags_to_button_state(
 			(fw->decor_state.buttons_inverted & mask),
 			(fw->decor_state.buttons_lit & mask),
-			(fw->decor_state.buttons_toggled & mask));
+			(fw->decor_state.buttons_toggled & mask),
+			(fw->decor_state.buttons_hover & mask));
 		if (old_state != td->tbstate.bstate[i])
 		{
 			draw_parts |= PART_BUTTONS;
@@ -4392,6 +4399,7 @@
 	fw->decor_state.buttons_inverted = td->tbstate.pressed_bmask;
 	fw->decor_state.buttons_lit = td->tbstate.lit_bmask;
 	fw->decor_state.buttons_toggled = td->tbstate.toggled_bmask;
+	fw->decor_state.buttons_hover = td->tbstate.hover_bmask;
 
 	return;
 }
@@ -4660,13 +4668,18 @@
 		{
 			tbstate->toggled_bmask |= mask;
 		}
+		if (FW_W_BUTTON(fw, i) == HoverW)
+		{
+			tbstate->hover_bmask |= mask;
+		}
 		tbstate->bstate[i] = border_flags_to_button_state(
 			tbstate->pressed_bmask & mask,
 			tbstate->lit_bmask & mask,
-			tbstate->toggled_bmask & mask);
+			tbstate->toggled_bmask & mask,
+			tbstate->hover_bmask & mask);
 	}
 	tbstate->tstate = border_flags_to_button_state(
-		tbstate->is_title_pressed, tbstate->is_title_lit, 0);
+		tbstate->is_title_pressed, tbstate->is_title_lit, 0, 0);
 }
 
 static window_parts border_get_titlebar_descr(
@@ -4931,6 +4944,7 @@
 		fw->decor_state.buttons_lit = 0;
 		fw->decor_state.buttons_inverted = 0;
 		fw->decor_state.buttons_toggled = 0;
+		fw->decor_state.buttons_hover = 0;
 		return;
 	}
 	memset(&td, 0, sizeof(td));
@@ -4982,6 +4996,7 @@
 		fw->decor_state.buttons_toggled =
 			(fw->decor_state.buttons_toggled &
 			 ~td.tbstate.max_bmask) | td.tbstate.toggled_bmask;
+		fw->decor_state.buttons_hover &= td.tbstate.hover_bmask;
 	}
 
 	return;
@@ -5072,11 +5087,12 @@
 	ButtonState bs;
 	int is_pressed;
 	int is_toggled;
+	int is_hover;
 	int i;
 
 	/* title */
 	is_pressed = (FW_W_TITLE(fw) == PressedW);
-	bs = border_flags_to_button_state(is_pressed, has_focus, 0);
+	bs = border_flags_to_button_state(is_pressed, has_focus, 0, 0);
 	if (DFS_USE_BORDER_STYLE(TB_STATE(GetDecor(fw, titlebar))[bs].style))
 	{
 		return 1;
@@ -5089,8 +5105,9 @@
 		}
 		is_pressed = (FW_W_BUTTON(fw, i) == PressedW);
 		is_toggled = (is_button_toggled(fw, i) == True);
+		is_hover = (FW_W_BUTTON(fw, i) == HoverW);
 		bs = border_flags_to_button_state(
-			is_pressed, (has_focus == True), is_toggled);
+			is_pressed, (has_focus == True), is_toggled, is_hover);
 		if (DFS_USE_BORDER_STYLE(
 			    TB_STATE(GetDecor(fw, buttons[i]))[bs].style))
 		{
@@ -5551,6 +5568,7 @@
 				DEFAULT_USE_INACTIVE_BUTTONS;
 			Scr.gs.use_inactive_down_buttons =
 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
+			Scr.gs.use_hover_buttons = 0;
 			return;
 		}
 		first = False;
@@ -5572,6 +5590,12 @@
 				action, &action,
 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS, True);
 		}
+		else if (StrEquals("hover", token))
+		{
+			Scr.gs.use_hover_buttons = ParseToggleArgument(
+				action, &action,
+				0, True);
+		}
 		else
 		{
 			Scr.gs.use_active_down_buttons =
@@ -5580,6 +5604,7 @@
 				DEFAULT_USE_INACTIVE_BUTTONS;
 			Scr.gs.use_inactive_down_buttons =
 				DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
+			Scr.gs.use_hover_buttons = 0;
 			fvwm_msg(ERR, "cmd_button_state",
 				 "Unknown button state %s", token);
 			return;
Only in fvwm-patched/fvwm: borders.c.orig
diff --unified --recursive --text fvwm-2.6.9/fvwm/builtins.c fvwm-patched/fvwm/builtins.c
--- fvwm-2.6.9/fvwm/builtins.c	2020-08-21 16:16:28.114047517 -0600
+++ fvwm-patched/fvwm/builtins.c	2020-08-21 16:34:52.530676541 -0600
@@ -94,12 +94,16 @@
 {
 	"ActiveUp",
 	"ActiveDown",
+	"ActiveHover",
 	"InactiveUp",
 	"InactiveDown",
+	"InactiveHover",
 	"ToggledActiveUp",
 	"ToggledActiveDown",
+	"ToggledActiveHover",
 	"ToggledInactiveUp",
 	"ToggledInactiveDown",
+	"ToggledInactiveHover",
 	"Active",
 	"Inactive",
 	"ToggledActive",
@@ -110,10 +114,13 @@
 	"AllInactive",
 	"AllUp",
 	"AllDown",
+	"AllHover",
 	"AllActiveUp",
 	"AllActiveDown",
+	"AllActiveHover",
 	"AllInactiveUp",
 	"AllInactiveDown",
+	"AllInactiveHover",
 	NULL
 };
 
Only in fvwm-patched/fvwm: builtins.c.orig
diff --unified --recursive --text fvwm-2.6.9/fvwm/events.c fvwm-patched/fvwm/events.c
--- fvwm-2.6.9/fvwm/events.c	2018-05-26 05:35:26.000000000 -0600
+++ fvwm-patched/fvwm/events.c	2020-08-21 16:38:28.601284882 -0600
@@ -184,6 +184,7 @@
 
 int last_event_type = 0;
 Window PressedW = None;
+Window HoverW = None;
 
 /* ---------------------------- local functions ---------------------------- */
 
@@ -1785,6 +1786,23 @@
 	return;
 }
 
+static void redraw_hover(FvwmWindow* fw, Window w)
+{
+	if (fw)
+	{
+		int i;
+		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
+		{
+			if (w == FW_W_BUTTON(fw, i))
+			{
+				HoverW = FW_W_BUTTON(fw, i);
+			}
+		}
+		border_redraw_decorations(fw);
+		HoverW = None;
+	}
+}
+
 /* ---------------------------- event handlers ----------------------------- */
 
 void HandleButtonPress(const evh_args_t *ea)
@@ -1980,6 +1998,8 @@
 	ewp = &te->xcrossing;
 ENTER_DBG((stderr, "++++++++ en (%d): fw %p w 0x%08x sw 0x%08x mode 0x%x detail 0x%x '%s'\n", ++ecount, fw, (int)ewp->window, (int)ewp->subwindow, ewp->mode, ewp->detail, fw?fw->visible_name:"(none)"));
 
+	redraw_hover(fw, ewp->window);
+
 	if (
 		ewp->window == Scr.Root &&
 		ewp->detail == NotifyInferior && ewp->mode == NotifyNormal)
@@ -2687,6 +2707,8 @@
 
 	DBUG("HandleLeaveNotify", "Routine Entered");
 
+	redraw_hover(fw, te->xcrossing.window);
+
 ENTER_DBG((stderr, "-------- ln (%d): fw %p w 0x%08x sw 0x%08x mode 0x%x detail 0x%x '%s'\n", ++ecount, fw, (int)te->xcrossing.window, (int)te->xcrossing.subwindow, te->xcrossing.mode, te->xcrossing.detail, fw?fw->visible_name:"(none)"));
 	lwp = &te->xcrossing;
 	if (
Only in fvwm-patched/fvwm: events.c.orig
diff --unified --recursive --text fvwm-2.6.9/fvwm/fvwm.h fvwm-patched/fvwm/fvwm.h
--- fvwm-2.6.9/fvwm/fvwm.h	2020-08-21 16:11:42.983734347 -0600
+++ fvwm-patched/fvwm/fvwm.h	2020-08-21 16:34:52.534676586 -0600
@@ -827,6 +827,7 @@
 		unsigned buttons_lit : NUMBER_OF_TITLE_BUTTONS;
 		unsigned buttons_inverted : NUMBER_OF_TITLE_BUTTONS;
 		unsigned buttons_toggled : NUMBER_OF_TITLE_BUTTONS;
+		unsigned buttons_hover : NUMBER_OF_TITLE_BUTTONS;
 		unsigned parts_drawn : 12;
 		unsigned parts_lit : 12;
 		unsigned parts_inverted : 12;
diff --unified --recursive --text fvwm-2.6.9/fvwm/screen.h fvwm-patched/fvwm/screen.h
--- fvwm-2.6.9/fvwm/screen.h	2020-08-21 16:16:28.118047433 -0600
+++ fvwm-patched/fvwm/screen.h	2020-08-21 16:34:52.534676586 -0600
@@ -202,12 +202,16 @@
 	BS_All = -1,
 	BS_ActiveUp,
 	BS_ActiveDown,
+	BS_ActiveHover,
 	BS_InactiveUp,
 	BS_InactiveDown,
+	BS_InactiveHover,
 	BS_ToggledActiveUp,
 	BS_ToggledActiveDown,
+	BS_ToggledActiveHover,
 	BS_ToggledInactiveUp,
 	BS_ToggledInactiveDown,
+	BS_ToggledInactiveHover,
 	BS_MaxButtonState,
 	BS_MaxButtonStateMask = BS_MaxButtonState - 1,
 	BS_Active,
@@ -220,10 +224,13 @@
 	BS_AllInactive,
 	BS_AllUp,
 	BS_AllDown,
+	BS_AllHover,
 	BS_AllActiveUp,
 	BS_AllActiveDown,
+	BS_AllActiveHover,
 	BS_AllInactiveUp,
 	BS_AllInactiveDown,
+	BS_AllInactiveHover,
 	BS_MaxButtonStateName
 } ButtonState;
 
@@ -511,6 +518,7 @@
 		unsigned use_active_down_buttons : 1;
 		unsigned use_inactive_buttons : 1;
 		unsigned use_inactive_down_buttons : 1;
+		unsigned use_hover_buttons : 1;
 	} gs; /* global style structure */
 	struct
 	{
Only in fvwm-patched/fvwm: screen.h.orig
