From d6a18d69c0c104a3f3ce3bb67d984b4479f6717e Mon Sep 17 00:00:00 2001
From: Alexander Courtis <alex@courtis.org>
Date: Thu, 30 Jul 2020 13:03:40 +1000
Subject: do not render frames when any surface has uncommitted resizes

---
 dwl.c | 40 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/dwl.c b/dwl.c
index 4cef058..2fb3399 100644
--- a/dwl.c
+++ b/dwl.c
@@ -75,6 +75,7 @@ typedef struct {
 		struct wlr_xwayland_surface *xwayland_surface;
 	};
 	struct wl_listener activate;
+	struct wl_listener commit;
 	struct wl_listener map;
 	struct wl_listener unmap;
 	struct wl_listener destroy;
@@ -84,6 +85,7 @@ typedef struct {
 	int bw;
 	unsigned int tags;
 	int isfloating;
+	uint32_t resize; /* configure serial of a pending resize */
 } Client;
 
 typedef struct {
@@ -442,6 +444,16 @@ cleanupmon(struct wl_listener *listener, void *data)
 	free(m);
 }
 
+void
+commitnotify(struct wl_listener *listener, void *data)
+{
+	Client *c = wl_container_of(listener, c, commit);
+
+	/* mark a pending resize as completed */
+	if (c->resize && c->resize <= c->xdg_surface->configure_serial)
+		c->resize = 0;
+}
+
 void
 createkeyboard(struct wlr_input_device *device)
 {
@@ -553,6 +565,8 @@ createnotify(struct wl_listener *listener, void *data)
 			WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
 
 	/* Listen to the various events it can emit */
+	c->commit.notify = commitnotify;
+	wl_signal_add(&xdg_surface->surface->events.commit, &c->commit);
 	c->map.notify = maprequest;
 	wl_signal_add(&xdg_surface->events.map, &c->map);
 	c->unmap.notify = unmapnotify;
@@ -628,6 +642,8 @@ destroynotify(struct wl_listener *listener, void *data)
 	wl_list_remove(&c->map.link);
 	wl_list_remove(&c->unmap.link);
 	wl_list_remove(&c->destroy.link);
+	if (c->type == XDGShell)
+		wl_list_remove(&c->commit.link);
 	if (c->type == X11Managed)
 		wl_list_remove(&c->activate.link);
 	free(c);
@@ -1220,6 +1236,8 @@ void
 rendermon(struct wl_listener *listener, void *data)
 {
 	struct wlr_output *output = data;
+	Client *c;
+	int render = 1;
 
 	/* This function is called every time an output is ready to display a frame,
 	 * generally at the output's refresh rate (e.g. 60Hz). */
@@ -1228,16 +1246,30 @@ rendermon(struct wl_listener *listener, void *data)
 	struct timespec now;
 	clock_gettime(CLOCK_MONOTONIC, &now);
 
+	/* Do not render if any XDG clients have an outstanding resize. */
+	wl_list_for_each(c, &stack, slink)
+	{
+		if (c->resize)
+		{
+			wlr_surface_send_frame_done(WLR_SURFACE(c), &now);
+			render = 0;
+		}
+	}
+
 	/* wlr_output_attach_render makes the OpenGL context current. */
 	if (!wlr_output_attach_render(m->wlr_output, NULL))
 		return;
 
 	/* Begin the renderer (calls glViewport and some other GL sanity checks) */
 	wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height);
-	wlr_renderer_clear(drw, rootcolor);
 
-	renderclients(m, &now);
-	renderindependents(output, &now);
+	if (render)
+	{
+		wlr_renderer_clear(drw, rootcolor);
+
+		renderclients(m, &now);
+		renderindependents(output, &now);
+	}
 
 	/* Hardware cursors are rendered by the GPU on a separate plane, and can be
 	 * moved around without re-rendering what's beneath them - which is more
@@ -1273,7 +1305,7 @@ resize(Client *c, int x, int y, int w, int h, int interact)
 				c->geom.x, c->geom.y,
 				c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
 	else
-		wlr_xdg_toplevel_set_size(c->xdg_surface,
+		c->resize = wlr_xdg_toplevel_set_size(c->xdg_surface,
 				c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
 }
 
-- 
cgit v1.2.3