Index: app/cwm/calmwm.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.c,v
retrieving revision 1.115
diff -u -p -r1.115 calmwm.c
--- app/cwm/calmwm.c	26 Feb 2022 15:19:18 -0000	1.115
+++ app/cwm/calmwm.c	18 Feb 2024 15:36:43 -0000
@@ -42,6 +42,7 @@ Atom			 cwmh[CWMH_NITEMS];
 Atom			 ewmh[EWMH_NITEMS];
 struct screen_q		 Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
 struct conf		 Conf;
+struct ar_ctx		 ar;
 volatile sig_atomic_t	 cwm_status;
 
 __dead void	usage(void);
@@ -50,6 +51,7 @@ static int	x_errorhandler(Display *, XEr
 static int	x_init(const char *);
 static void	x_teardown(void);
 static int	x_wmerrorhandler(Display *, XErrorEvent *);
+void		ar_clear(void);
 
 int
 main(int argc, char **argv)
@@ -63,6 +65,8 @@ main(int argc, char **argv)
 		warnx("no locale support");
 	mbtowc(NULL, NULL, MB_CUR_MAX);
 
+	ar_clear();
+
 	conf_init(&Conf);
 
 	fallback = u_argv(argv);
@@ -114,9 +118,17 @@ main(int argc, char **argv)
 	pfd[0].events = POLLIN;
 	while (cwm_status == CWM_RUNNING) {
 		xev_process();
-		if (poll(pfd, 1, INFTIM) == -1) {
+		switch (poll(pfd, 1, ar.delta)) {
+		case 0:
+			if (ar.cc != NULL) {
+				client_raise(ar.cc);
+				ar_clear();
+			}
+			break;
+		case -1:
 			if (errno != EINTR)
 				warn("poll");
+			break;
 		}
 	}
 	x_teardown();
@@ -224,6 +236,14 @@ sighdlr(int sig)
 	}
 
 	errno = save_errno;
+}
+
+void
+ar_clear(void)
+{
+	ar.cc = NULL;
+	ar.delta = INFTIM;
+	(void)memset(&ar.start, 0, sizeof(ar.start));
 }
 
 __dead void
Index: app/cwm/calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.379
diff -u -p -r1.379 calmwm.h
--- app/cwm/calmwm.h	20 Jul 2023 14:39:34 -0000	1.379
+++ app/cwm/calmwm.h	18 Feb 2024 15:36:43 -0000
@@ -306,6 +306,14 @@ struct conf {
 	char			*known_hosts;
 	char			*wm_argv;
 	int			 debug;
+	int			 autoraise;
+	int			 raisedelay;
+};
+
+struct ar_ctx {
+	struct client_ctx	*cc;
+	struct timeval		 start;
+	int			 delta;
 };
 
 /* MWM hints */
@@ -397,6 +405,9 @@ extern Atom				 cwmh[CWMH_NITEMS];
 extern Atom				 ewmh[EWMH_NITEMS];
 extern struct screen_q			 Screenq;
 extern struct conf			 Conf;
+extern struct ar_ctx			 ar;
+
+void			 ar_clear(void);
 
 void			 client_apply_sizehints(struct client_ctx *);
 void			 client_close(struct client_ctx *);
Index: app/cwm/conf.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/conf.c,v
retrieving revision 1.256
diff -u -p -r1.256 conf.c
--- app/cwm/conf.c	20 Jul 2023 14:39:34 -0000	1.256
+++ app/cwm/conf.c	18 Feb 2024 15:36:43 -0000
@@ -293,6 +293,8 @@ conf_init(struct conf *c)
 	c->snapdist = 0;
 	c->ngroups = 0;
 	c->nameqlen = 5;
+	c->autoraise = 0;
+	c->raisedelay = 0;
 
 	TAILQ_INIT(&c->ignoreq);
 	TAILQ_INIT(&c->autogroupq);
Index: app/cwm/cwmrc.5
===================================================================
RCS file: /cvs/xenocara/app/cwm/cwmrc.5,v
retrieving revision 1.78
diff -u -p -r1.78 cwmrc.5
--- app/cwm/cwmrc.5	20 Jul 2023 14:39:34 -0000	1.78
+++ app/cwm/cwmrc.5	18 Feb 2024 15:36:43 -0000
@@ -60,6 +60,11 @@ used to override
 The name and class values, respectively, for existing windows
 are both set in the WM_CLASS property and may be obtained using
 .Xr xprop 1 .
+.It Ic autoraise Ic yes Ns \&| Ns Ic no
+A window gets raised automatically
+.Ic raisedelay
+milliseconds after the mouse pointer enters.
+.Pp
 .It Ic bind-key Ar key function
 Bind or rebind key
 .Ar key
@@ -194,10 +199,19 @@ The default is 50.
 Ignore, and do not warp to, windows with the name
 .Ar windowname
 when drawing borders and cycling through windows.
+The
+.Dq autoraise
+function honors this setting.
 .It Ic moveamount Ar pixels
 Set a default size for the keyboard movement bindings,
 in pixels.
 The default is 1.
+.It Ic raisedelay Ar ms
+If
+.Ic autoraise
+is enabled the automatic raise of a window is delayed for
+.Ar ms
+milliseconds.
 .It Ic snapdist Ar pixels
 Minimum distance to snap-to adjacent edge, in pixels.
 The default is 0.
Index: app/cwm/kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
retrieving revision 1.174
diff -u -p -r1.174 kbfunc.c
--- app/cwm/kbfunc.c	20 Jul 2023 14:39:34 -0000	1.174
+++ app/cwm/kbfunc.c	18 Feb 2024 15:36:43 -0000
@@ -141,6 +141,8 @@ kbfunc_client_move_kb(void *ctx, struct 
 	    area.y, area.y + area.h, sc->snapdist);
 
 	client_move(cc);
+	if (Conf.autoraise)
+		XSync(X_Dpy, True);
 	client_ptr_inbound(cc, 1);
 	XSync(X_Dpy, True);
 }
Index: app/cwm/parse.y
===================================================================
RCS file: /cvs/xenocara/app/cwm/parse.y,v
retrieving revision 1.75
diff -u -p -r1.75 parse.y
--- app/cwm/parse.y	24 Dec 2021 16:00:47 -0000	1.75
+++ app/cwm/parse.y	18 Feb 2024 15:36:43 -0000
@@ -78,6 +78,7 @@ typedef struct {
 %token	MENUBG MENUFG
 %token	FONTCOLOR FONTSELCOLOR
 %token	ERROR
+%token	AUTORAISE RAISEDELAY
 %token	<v.string>		STRING
 %token	<v.number>		NUMBER
 %type	<v.number>		yesno
@@ -126,6 +127,16 @@ main		: FONTNAME STRING		{
 		| STICKY yesno {
 			conf->stickygroups = $2;
 		}
+		| AUTORAISE yesno {
+			conf->autoraise = $2;
+		}
+		| RAISEDELAY NUMBER {
+			if ($2 < 0 || $2 > INT_MAX) {
+				yyerror("invalid raisedelay");
+				YYERROR;
+			}
+			conf->raisedelay = $2;
+		}
 		| BORDERWIDTH NUMBER {
 			if ($2 < 0 || $2 > INT_MAX) {
 				yyerror("invalid borderwidth");
@@ -332,6 +343,7 @@ lookup(char *s)
 	static const struct keywords keywords[] = {
 		{ "activeborder",	ACTIVEBORDER},
 		{ "autogroup",		AUTOGROUP},
+		{ "autoraise",		AUTORAISE},
 		{ "bind-key",		BINDKEY},
 		{ "bind-mouse",		BINDMOUSE},
 		{ "borderwidth",	BORDERWIDTH},
@@ -348,6 +360,7 @@ lookup(char *s)
 		{ "menufg",		MENUFG},
 		{ "moveamount",		MOVEAMOUNT},
 		{ "no",			NO},
+		{ "raisedelay",		RAISEDELAY},
 		{ "selfont", 		FONTSELCOLOR},
 		{ "snapdist",		SNAPDIST},
 		{ "sticky",		STICKY},
Index: app/cwm/xevents.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/xevents.c,v
retrieving revision 1.150
diff -u -p -r1.150 xevents.c
--- app/cwm/xevents.c	24 Mar 2020 14:47:29 -0000	1.150
+++ app/cwm/xevents.c	18 Feb 2024 15:36:43 -0000
@@ -26,6 +26,7 @@
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <err.h>
 #include <errno.h>
@@ -43,6 +44,7 @@ static void	 xev_handle_destroynotify(XE
 static void	 xev_handle_configurerequest(XEvent *);
 static void	 xev_handle_propertynotify(XEvent *);
 static void	 xev_handle_enternotify(XEvent *);
+static void	 xev_handle_leavenotify(XEvent *);
 static void	 xev_handle_buttonpress(XEvent *);
 static void	 xev_handle_buttonrelease(XEvent *);
 static void	 xev_handle_keypress(XEvent *);
@@ -51,6 +53,8 @@ static void	 xev_handle_clientmessage(XE
 static void	 xev_handle_randr(XEvent *);
 static void	 xev_handle_mappingnotify(XEvent *);
 static void	 xev_handle_expose(XEvent *);
+static void	 xev_handle_timer();
+static void	 xev_delete_timer(struct client_ctx *);
 
 void		(*xev_handlers[LASTEvent])(XEvent *) = {
 			[MapRequest] = xev_handle_maprequest,
@@ -59,6 +63,7 @@ void		(*xev_handlers[LASTEvent])(XEvent 
 			[ConfigureRequest] = xev_handle_configurerequest,
 			[PropertyNotify] = xev_handle_propertynotify,
 			[EnterNotify] = xev_handle_enternotify,
+			[LeaveNotify] = xev_handle_leavenotify,
 			[ButtonPress] = xev_handle_buttonpress,
 			[ButtonRelease] = xev_handle_buttonrelease,
 			[KeyPress] = xev_handle_keypress,
@@ -229,8 +234,33 @@ xev_handle_enternotify(XEvent *ee)
 
 	Last_Event_Time = e->time;
 
+	if ((cc = client_find(e->window)) == NULL)
+		return;
+
+	if (Conf.autoraise &&
+	    (!(cc->flags & CLIENT_IGNORE)) &&
+	    (e->detail != NotifyInferior)) {
+		if (Conf.raisedelay > 0) {
+			gettimeofday(&ar.start, NULL);
+			ar.cc = cc;
+		} else
+			client_raise(cc);
+	}
+
+	client_set_active(cc);
+}
+
+static void
+xev_handle_leavenotify(XEvent *ee)
+{
+	XCrossingEvent		*e = &ee->xcrossing;
+	struct client_ctx	*cc;
+
+	if (ar.cc == NULL)
+		return;
+
 	if ((cc = client_find(e->window)) != NULL)
-		client_set_active(cc);
+		xev_delete_timer(cc);
 }
 
 static void
@@ -479,6 +509,32 @@ xev_handle_expose(XEvent *ee)
 }
 
 void
+xev_delete_timer(struct client_ctx *cc)
+{
+	if (ar.cc != NULL && cc == ar.cc)
+		ar_clear();
+}
+
+static void
+xev_handle_timer(void)
+{
+	int		a;
+	int		d;
+	struct timeval	now;
+
+	gettimeofday(&now, NULL);
+	d = (now.tv_sec - ar.start.tv_sec) * 1000;
+	if ((a = now.tv_usec - ar.start.tv_usec) < 0)
+		a += 1000000;
+	d += a / 1000;
+	if (d >= Conf.raisedelay) {
+		client_raise(ar.cc);
+		xev_delete_timer(ar.cc);
+	} else
+		ar.delta = Conf.raisedelay - d;
+}
+
+void
 xev_process(void)
 {
 	XEvent		 e;
@@ -489,5 +545,7 @@ xev_process(void)
 			xev_handle_randr(&e);
 		else if ((e.type < LASTEvent) && (xev_handlers[e.type] != NULL))
 			(*xev_handlers[e.type])(&e);
+		if (ar.cc != NULL)
+			xev_handle_timer();
 	}
 }
