From 66bf55930f25fc4aba42fc7e21003b271e693aa1 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <djpohly@gmail.com>
Date: Thu, 23 Apr 2020 20:56:28 -0500
Subject: change focus(NULL, NULL) to mean unfocus

"Focus the most recently focused window on selmon" is now refocus()
---
 dwl.c | 101 ++++++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 55 insertions(+), 46 deletions(-)

diff --git a/dwl.c b/dwl.c
index a8633e8..fd4ef47 100644
--- a/dwl.c
+++ b/dwl.c
@@ -145,6 +145,7 @@ static void motionnotify(uint32_t time);
 static void motionrelative(struct wl_listener *listener, void *data);
 static void movemouse(const Arg *arg);
 static void quit(const Arg *arg);
+static void refocus(void);
 static void render(struct wlr_surface *surface, int sx, int sy, void *data);
 static void rendermon(struct wl_listener *listener, void *data);
 static void resize(Client *c, int x, int y, int w, int h);
@@ -233,14 +234,14 @@ buttonpress(struct wl_listener *listener, void *data)
 			event->time_msec, event->button, event->state);
 	double sx, sy;
 	struct wlr_surface *surface;
-	Client *c = xytoclient(cursor->x, cursor->y,
-			&surface, &sx, &sy);
+	Client *c = xytoclient(cursor->x, cursor->y, &surface, &sx, &sy);
 	if (event->state == WLR_BUTTON_RELEASED) {
 		/* If you released any buttons, we exit interactive move/resize mode. */
 		cursor_mode = CurNormal;
 	} else {
-		/* Focus that client if the button was _pressed_ */
-		focus(c, surface);
+		/* Change focus if the button was _pressed_ over a client */
+		if (c)
+			focus(c, surface);
 
 		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
 		uint32_t mods = wlr_keyboard_get_modifiers(keyboard);
@@ -410,26 +411,17 @@ dirtomon(int dir)
 void
 focus(Client *c, struct wlr_surface *surface)
 {
-	/* Default client is most recently focused on selmon */
-	if (!c || !VISIBLEON(c, c->mon)) {
-		c = NULL;
-		surface = NULL;
-		Client *next;
-		wl_list_for_each(next, &fstack, flink) {
-			if (VISIBLEON(next, selmon)) {
-				c = next;
-				break;
-			}
-		}
-	}
-	/* Default surface is the client's main xdg_surface */
-	if (c && !surface)
-		surface = c->xdg_surface->surface;
-
-	/* Focus the correct monitor as well */
-	if (c)
+	if (c) {
+		/* assert(VISIBLEON(c, c->mon)); ? */
+		/* Default surface is the client's main xdg_surface */
+		if (!surface)
+			surface = c->xdg_surface->surface;
+		/* Focus the correct monitor as well */
 		selmon = c->mon;
+	}
 
+	/* XXX Need to understand xdg toplevel/popups to know if there's more
+	 * simplification that can be done in this function */
 	struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
 	if (prev_surface == surface) {
 		/* Don't re-focus an already focused surface. */
@@ -445,25 +437,26 @@ focus(Client *c, struct wlr_surface *surface)
 					seat->keyboard_state.focused_surface);
 		wlr_xdg_toplevel_set_activated(previous, false);
 	}
-	if (c) {
-		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
-		/* Move the client to the front of the focus stack */
-		wl_list_remove(&c->flink);
-		wl_list_insert(&fstack, &c->flink);
-		/* Activate the new surface */
-		wlr_xdg_toplevel_set_activated(c->xdg_surface, true);
-		/*
-		 * Tell the seat to have the keyboard enter this surface.
-		 * wlroots will keep track of this and automatically send key
-		 * events to the appropriate clients without additional work on
-		 * your part.
-		 */
-		wlr_seat_keyboard_notify_enter(seat, c->xdg_surface->surface,
-			keyboard->keycodes, keyboard->num_keycodes,
-			&keyboard->modifiers);
-	} else {
+	if (!c) {
 		wlr_seat_keyboard_clear_focus(seat);
+		return;
 	}
+
+	struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
+	/* Move the client to the front of the focus stack */
+	wl_list_remove(&c->flink);
+	wl_list_insert(&fstack, &c->flink);
+	/* Activate the new surface */
+	wlr_xdg_toplevel_set_activated(c->xdg_surface, true);
+	/*
+	 * Tell the seat to have the keyboard enter this surface.
+	 * wlroots will keep track of this and automatically send key
+	 * events to the appropriate clients without additional work on
+	 * your part.
+	 */
+	wlr_seat_keyboard_notify_enter(seat, c->xdg_surface->surface,
+		keyboard->keycodes, keyboard->num_keycodes,
+		&keyboard->modifiers);
 }
 
 void
@@ -474,7 +467,7 @@ focusmon(const Arg *arg)
 	if (m == selmon)
 		return;
 	selmon = m;
-	focus(NULL, NULL);
+	refocus();
 }
 
 void
@@ -673,6 +666,9 @@ motionnotify(uint32_t time)
 		/* Clear pointer focus so future button events and such are not sent to
 		 * the last client to have the cursor over it. */
 		wlr_seat_pointer_clear_focus(seat);
+		/* If keyboard focus follows mouse, clear that too */
+		if (sloppyfocus)
+			focus(NULL, NULL);
 		return;
 	}
 
@@ -738,6 +734,19 @@ quit(const Arg *arg)
 	wl_display_terminate(wl_display);
 }
 
+void
+refocus(void)
+{
+	Client *c = NULL, *next;
+	wl_list_for_each(next, &fstack, flink) {
+		if (VISIBLEON(next, selmon)) {
+			c = next;
+			break;
+		}
+	}
+	focus(c, NULL);
+}
+
 void
 render(struct wlr_surface *surface, int sx, int sy, void *data)
 {
@@ -973,7 +982,7 @@ sendmon(Client *c, Monitor *m)
 	c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
 
 	if (c == selclient())
-		focus(NULL, NULL);
+		refocus();
 }
 
 void
@@ -1138,7 +1147,7 @@ tag(const Arg *arg)
 	Client *sel = selclient();
 	if (sel && arg->ui & TAGMASK) {
 		sel->tags = arg->ui & TAGMASK;
-		focus(NULL, NULL);
+		refocus();
 	}
 }
 
@@ -1207,7 +1216,7 @@ toggletag(const Arg *arg)
 	newtags = sel->tags ^ (arg->ui & TAGMASK);
 	if (newtags) {
 		sel->tags = newtags;
-		focus(NULL, NULL);
+		refocus();
 	}
 }
 
@@ -1218,7 +1227,7 @@ toggleview(const Arg *arg)
 
 	if (newtagset) {
 		selmon->tagset[selmon->seltags] = newtagset;
-		focus(NULL, NULL);
+		refocus();
 	}
 }
 
@@ -1232,7 +1241,7 @@ unmapnotify(struct wl_listener *listener, void *data)
 	wl_list_remove(&c->flink);
 
 	if (hadfocus)
-		focus(NULL, NULL);
+		refocus();
 }
 
 void
@@ -1243,7 +1252,7 @@ view(const Arg *arg)
 	selmon->seltags ^= 1; /* toggle sel tagset */
 	if (arg->ui & TAGMASK)
 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
-	focus(NULL, NULL);
+	refocus();
 }
 
 Client *
-- 
cgit v1.2.3