xdg-shell: Rework the state system

The states system, so far, has been a complicated mix of weird APIs
that solved a real race condition, but have been particularly ugly
for both compositors and clients to implement.
diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 0d4673b..165ce10 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -268,40 +268,39 @@
 
 static void
 handle_surface_configure(void *data, struct xdg_surface *surface,
-			 int32_t width, int32_t height)
+			 int32_t width, int32_t height,
+			 struct wl_array *states, uint32_t serial)
 {
 	struct window *window = data;
+	uint32_t *p;
 
-	if (window->native)
-		wl_egl_window_resize(window->native, width, height, 0, 0);
-
-	window->geometry.width = width;
-	window->geometry.height = height;
-
-	if (!window->fullscreen)
-		window->window_size = window->geometry;
-}
-
-static void
-handle_surface_change_state(void *data, struct xdg_surface *xdg_surface,
-			    uint32_t state,
-			    uint32_t value,
-			    uint32_t serial)
-{
-	struct window *window = data;
-
-	switch (state) {
-	case XDG_SURFACE_STATE_FULLSCREEN:
-		window->fullscreen = value;
-
-		if (!value)
-			handle_surface_configure(window, window->xdg_surface,
-						 window->window_size.width,
-						 window->window_size.height);
-		break;
+	window->fullscreen = 0;
+	wl_array_for_each(p, states) {
+		uint32_t state = *p;
+		switch (state) {
+		case XDG_SURFACE_STATE_FULLSCREEN:
+			window->fullscreen = 1;
+			break;
+		}
 	}
 
-	xdg_surface_ack_change_state(xdg_surface, state, value, serial);
+	if (width > 0 && height > 0) {
+		if (!window->fullscreen) {
+			window->window_size.width = width;
+			window->window_size.height = height;
+		}
+		window->geometry.width = width;
+		window->geometry.height = height;
+	} else if (!window->fullscreen) {
+		window->geometry = window->window_size;
+	}
+
+	if (window->native)
+		wl_egl_window_resize(window->native,
+				     window->geometry.width,
+				     window->geometry.height, 0, 0);
+
+	xdg_surface_ack_configure(surface, serial);
 }
 
 static void
@@ -322,7 +321,6 @@
 
 static const struct xdg_surface_listener xdg_surface_listener = {
 	handle_surface_configure,
-	handle_surface_change_state,
 	handle_surface_activated,
 	handle_surface_deactivated,
 	handle_surface_delete,
@@ -343,8 +341,8 @@
 
 	window->native =
 		wl_egl_window_create(window->surface,
-				     window->window_size.width,
-				     window->window_size.height);
+				     window->geometry.width,
+				     window->geometry.height);
 	window->egl_surface =
 		eglCreateWindowSurface(display->egl.dpy,
 				       display->egl.conf,
@@ -359,9 +357,8 @@
 	if (!window->frame_sync)
 		eglSwapInterval(display->egl.dpy, 0);
 
-	xdg_surface_request_change_state(window->xdg_surface,
-					 XDG_SURFACE_STATE_FULLSCREEN,
-					 window->fullscreen, 0);
+	if (window->fullscreen)
+		xdg_surface_set_fullscreen(window->xdg_surface, NULL);
 }
 
 static void
@@ -620,11 +617,12 @@
 {
 	struct display *d = data;
 
-	if (key == KEY_F11 && state)
-		xdg_surface_request_change_state(d->window->xdg_surface,
-						 XDG_SURFACE_STATE_FULLSCREEN,
-						 !d->window->fullscreen, 0);
-	else if (key == KEY_ESC && state)
+	if (key == KEY_F11 && state) {
+		if (d->window->fullscreen)
+			xdg_surface_unset_fullscreen(d->window->xdg_surface);
+		else
+			xdg_surface_set_fullscreen(d->window->xdg_surface, NULL);
+	} else if (key == KEY_ESC && state)
 		running = 0;
 }
 
@@ -772,8 +770,9 @@
 
 	window.display = &display;
 	display.window = &window;
-	window.window_size.width  = 250;
-	window.window_size.height = 250;
+	window.geometry.width  = 250;
+	window.geometry.height = 250;
+	window.window_size = window.geometry;
 	window.buffer_size = 32;
 	window.frame_sync = 1;