diff options
Diffstat (limited to 'tests/viewporter-test.c')
-rw-r--r-- | tests/viewporter-test.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/tests/viewporter-test.c b/tests/viewporter-test.c new file mode 100644 index 00000000..95fb9b46 --- /dev/null +++ b/tests/viewporter-test.c @@ -0,0 +1,553 @@ +/* + * Copyright © 2014, 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <time.h> + +#include "shared/helpers.h" +#include "shared/xalloc.h" +#include "weston-test-client-helper.h" +#include "viewporter-client-protocol.h" + +static struct wp_viewporter * +get_viewporter(struct client *client) +{ + struct global *g; + struct global *global_wpr = NULL; + static struct wp_viewporter *wpr; + + if (wpr) + return wpr; + + wl_list_for_each(g, &client->global_list, link) { + if (strcmp(g->interface, wp_viewporter_interface.name)) + continue; + + if (global_wpr) + assert(0 && "multiple wp_viewporter objects"); + + global_wpr = g; + } + + assert(global_wpr && "no wp_viewporter found"); + + assert(global_wpr->version == 1); + + wpr = wl_registry_bind(client->wl_registry, global_wpr->name, + &wp_viewporter_interface, 1); + assert(wpr); + + return wpr; +} + +static struct wp_viewport * +create_viewport(struct client *client) +{ + struct wp_viewporter *viewporter; + struct wp_viewport *viewport; + + viewporter = get_viewporter(client); + viewport = wp_viewporter_get_viewport(viewporter, + client->surface->wl_surface); + assert(viewport); + + return viewport; +} + +static void +set_source(struct wp_viewport *vp, int x, int y, int w, int h) +{ + wp_viewport_set_source(vp, wl_fixed_from_int(x), wl_fixed_from_int(y), + wl_fixed_from_int(w), wl_fixed_from_int(h)); +} + +TEST(test_viewporter_double_create) +{ + struct wp_viewporter *viewporter; + struct client *client; + + client = create_client_and_test_surface(100, 50, 123, 77); + + viewporter = get_viewporter(client); + wp_viewporter_get_viewport(viewporter, client->surface->wl_surface); + wp_viewporter_get_viewport(viewporter, client->surface->wl_surface); + + expect_protocol_error(client, &wp_viewporter_interface, + WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS); +} + +struct bad_source_rect_args { + int x, y, w, h; +}; + +static const struct bad_source_rect_args bad_source_rect_args[] = { + { -5, 0, 20, 10 }, + { 0, -5, 20, 10 }, + { 5, 6, 0, 10 }, + { 5, 6, 20, 0 }, + { 5, 6, -20, 10 }, + { 5, 6, 20, -10 }, + { -1, -1, 20, 10 }, + { 5, 6, -1, -1 }, +}; + +TEST_P(test_viewporter_bad_source_rect, bad_source_rect_args) +{ + const struct bad_source_rect_args *args = data; + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + + vp = create_viewport(client); + + fprintf(stderr, "wp_viewport.set_source x=%d, y=%d, w=%d, h=%d\n", + args->x, args->y, args->w, args->h); + set_source(vp, args->x, args->y, args->w, args->h); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_BAD_VALUE); +} + +TEST(test_viewporter_unset_source_rect) +{ + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + + vp = create_viewport(client); + set_source(vp, -1, -1, -1, -1); + wl_surface_commit(client->surface->wl_surface); + + client_roundtrip(client); +} + +struct bad_destination_args { + int w, h; +}; + +static const struct bad_destination_args bad_destination_args[] = { + { 0, 10 }, + { 20, 0 }, + { -20, 10 }, + { -1, 10 }, + { 20, -10 }, + { 20, -1 }, +}; + +TEST_P(test_viewporter_bad_destination_size, bad_destination_args) +{ + const struct bad_destination_args *args = data; + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + + vp = create_viewport(client); + + fprintf(stderr, "wp_viewport.set_destination w=%d, h=%d\n", + args->w, args->h); + wp_viewport_set_destination(vp, args->w, args->h); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_BAD_VALUE); +} + +TEST(test_viewporter_unset_destination_size) +{ + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + + vp = create_viewport(client); + wp_viewport_set_destination(vp, -1, -1); + wl_surface_commit(client->surface->wl_surface); + + client_roundtrip(client); +} + +struct nonint_destination_args { + wl_fixed_t w, h; +}; + +static const struct nonint_destination_args nonint_destination_args[] = { +#define F(i,f) ((i) * 256 + (f)) + { F(20, 0), F(10, 1) }, + { F(20, 0), F(10, -1) }, + { F(20, 1), F(10, 0) }, + { F(20, -1), F(10, 0) }, + { F(20, 128), F(10, 128) }, +#undef F +}; + +TEST_P(test_viewporter_non_integer_destination_size, nonint_destination_args) +{ + const struct nonint_destination_args *args = data; + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + + vp = create_viewport(client); + + fprintf(stderr, "non-integer size w=%f, h=%f\n", + wl_fixed_to_double(args->w), wl_fixed_to_double(args->h)); + wp_viewport_set_source(vp, 5, 6, args->w, args->h); + wp_viewport_set_destination(vp, -1, -1); + wl_surface_commit(client->surface->wl_surface); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_BAD_SIZE); +} + +struct source_buffer_args { + wl_fixed_t x, y; + wl_fixed_t w, h; + int buffer_scale; + enum wl_output_transform buffer_transform; +}; + +static int +get_surface_width(struct surface *surface, + int buffer_scale, + enum wl_output_transform buffer_transform) +{ + switch (buffer_transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + case WL_OUTPUT_TRANSFORM_180: + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + return surface->width / buffer_scale; + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + return surface->height / buffer_scale; + } + + return -1; +} + +static int +get_surface_height(struct surface *surface, + int buffer_scale, + enum wl_output_transform buffer_transform) +{ + switch (buffer_transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + case WL_OUTPUT_TRANSFORM_180: + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + return surface->height / buffer_scale; + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + return surface->width / buffer_scale; + } + + return -1; +} + +static void +setup_source_vs_buffer(struct client *client, + const struct source_buffer_args *args) +{ + struct wl_surface *surf; + struct wp_viewport *vp; + + surf = client->surface->wl_surface; + vp = create_viewport(client); + + fprintf(stderr, "surface %dx%d\n", + get_surface_width(client->surface, + args->buffer_scale, args->buffer_transform), + get_surface_height(client->surface, + args->buffer_scale, args->buffer_transform)); + fprintf(stderr, "source x=%f, y=%f, w=%f, h=%f; " + "buffer scale=%d, transform=%d\n", + wl_fixed_to_double(args->x), wl_fixed_to_double(args->y), + wl_fixed_to_double(args->w), wl_fixed_to_double(args->h), + args->buffer_scale, args->buffer_transform); + + wl_surface_set_buffer_scale(surf, args->buffer_scale); + wl_surface_set_buffer_transform(surf, args->buffer_transform); + wl_surface_attach(surf, client->surface->buffer->proxy, 0, 0); + wp_viewport_set_source(vp, args->x, args->y, args->w, args->h); + wp_viewport_set_destination(vp, 99, 99); + wl_surface_commit(surf); +} + +/* buffer dimensions */ +#define WIN_W 124 +#define WIN_H 78 + +/* source rect base size */ +#define SRC_W 20 +#define SRC_H 10 + +/* margin */ +#define MRG 10 +/* epsilon of wl_fixed_t */ +#define EPS 1 + +TEST(test_viewporter_source_buffer_params) +{ + const int max_scale = 2; + + /* buffer_scale requirement */ + assert(WIN_W % max_scale == 0); + assert(WIN_H % max_scale == 0); + + /* source rect must fit inside regardless of scale and transform */ + assert(SRC_W < WIN_W / max_scale); + assert(SRC_H < WIN_H / max_scale); + assert(SRC_W < WIN_H / max_scale); + assert(SRC_H < WIN_W / max_scale); + + /* If buffer scale was ignored, source rect should be inside instead */ + assert(WIN_W / max_scale + SRC_W + MRG < WIN_W); + assert(WIN_H / max_scale + SRC_H + MRG < WIN_H); + assert(WIN_W / max_scale + SRC_H + MRG < WIN_W); + assert(WIN_H / max_scale + SRC_W + MRG < WIN_H); +} + +static const struct source_buffer_args bad_source_buffer_args[] = { +#define F(i) ((i) * 256) + +/* Flush right-top, but epsilon too far right. */ + { F(WIN_W - SRC_W) + EPS, F(0), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W - SRC_W), F(0), F(SRC_W) + EPS, F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, +/* Flush left-bottom, but epsilon too far down. */ + { F(0), F(WIN_H - SRC_H) + EPS, F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(0), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H) + EPS, 1, WL_OUTPUT_TRANSFORM_NORMAL }, +/* Completely outside on the right. */ + { F(WIN_W + MRG), F(0), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, +/* Competely outside on the bottom. */ + { F(0), F(WIN_H + MRG), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + +/* + * buffer_scale=2, so the surface size will be halved. + * If buffer_scale was not taken into account, these would all be inside. + * These are the same as above, but adapted to buffer_scale=2. + */ + { F(WIN_W / 2 - SRC_W) + EPS, F(0), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W / 2 - SRC_W), F(0), F(SRC_W) + EPS, F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + + { F(0), F(WIN_H / 2 - SRC_H) + EPS, F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(0), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H) + EPS, 2, WL_OUTPUT_TRANSFORM_NORMAL }, + + { F(WIN_W / 2 + MRG), F(0), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + + { F(0), F(WIN_H / 2 + MRG), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + +/* Exceeding bottom-right corner by epsilon: */ +/* non-dimension-swapping transforms */ + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H) + EPS, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180 }, + { F(WIN_W - SRC_W), F(WIN_H - SRC_H) + EPS, F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED }, + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W) + EPS, F(SRC_H), 1, WL_OUTPUT_TRANSFORM_180 }, + +/* dimension-swapping transforms */ + { F(WIN_H - SRC_W) + EPS, F(WIN_W - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_90 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H) + EPS, F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_270 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W) + EPS, F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED_90 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W), F(SRC_H) + EPS, 1, WL_OUTPUT_TRANSFORM_FLIPPED_270 }, + +/* non-dimension-swapping transforms, buffer_scale=2 */ + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H) + EPS, F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED_180 }, + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W) + EPS, F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED }, + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H) + EPS, 2, WL_OUTPUT_TRANSFORM_180 }, + +/* dimension-swapping transforms, buffer_scale=2 */ + { F(WIN_H / 2 - SRC_W) + EPS, F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_90 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H) + EPS, F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_270 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W) + EPS, F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED_90 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H) + EPS, 2, WL_OUTPUT_TRANSFORM_FLIPPED_270 }, + +#undef F +}; + +TEST_P(test_viewporter_source_outside_buffer, bad_source_buffer_args) +{ + const struct source_buffer_args *args = data; + struct client *client; + + client = create_client_and_test_surface(100, 50, WIN_W, WIN_H); + setup_source_vs_buffer(client, args); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_OUT_OF_BUFFER); +} + +static const struct source_buffer_args good_source_buffer_args[] = { +#define F(i) ((i) * 256) + +/* top-left, top-right, bottom-left, and bottom-right corner */ + { F(0), F(0), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W - SRC_W), F(0), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(0), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_NORMAL }, + +/* buffer_scale=2, so the surface size will be halved */ + { F(0), F(0), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W / 2 - SRC_W), F(0), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(0), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_NORMAL }, + +/* with half pixel offset */ + { F(WIN_W / 2 - SRC_W) + 128, F(WIN_H / 2 - SRC_H) + 128, F(SRC_W) - 128, F(SRC_H) - 128, 2, WL_OUTPUT_TRANSFORM_NORMAL }, + +/* Flushed to bottom-right corner: */ +/* non-dimension-swapping transforms */ + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED_180 }, + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED }, + { F(WIN_W - SRC_W), F(WIN_H - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_180 }, + +/* dimension-swapping transforms */ + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_90 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_270 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED_90 }, + { F(WIN_H - SRC_W), F(WIN_W - SRC_H), F(SRC_W), F(SRC_H), 1, WL_OUTPUT_TRANSFORM_FLIPPED_270 }, + +/* non-dimension-swapping transforms, buffer_scale=2 */ + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED_180 }, + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED }, + { F(WIN_W / 2 - SRC_W), F(WIN_H / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_180 }, + +/* dimension-swapping transforms, buffer_scale=2 */ + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_90 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_270 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED_90 }, + { F(WIN_H / 2 - SRC_W), F(WIN_W / 2 - SRC_H), F(SRC_W), F(SRC_H), 2, WL_OUTPUT_TRANSFORM_FLIPPED_270 }, + +#undef F +}; + +TEST_P(test_viewporter_source_inside_buffer, good_source_buffer_args) +{ + const struct source_buffer_args *args = data; + struct client *client; + + client = create_client_and_test_surface(100, 50, WIN_W, WIN_H); + setup_source_vs_buffer(client, args); + client_roundtrip(client); +} + +#undef WIN_W +#undef WIN_H +#undef SRC_W +#undef SRC_H +#undef MRG +#undef EPS + +TEST(test_viewporter_outside_null_buffer) +{ + struct client *client; + struct wp_viewport *vp; + struct wl_surface *surf; + + client = create_client_and_test_surface(100, 50, 123, 77); + surf = client->surface->wl_surface; + + /* If buffer is NULL, does not matter what the source rect is. */ + vp = create_viewport(client); + wl_surface_attach(surf, NULL, 0, 0); + set_source(vp, 1000, 1000, 20, 10); + wp_viewport_set_destination(vp, 99, 99); + wl_surface_commit(surf); + client_roundtrip(client); + + /* Try again, with all old values. */ + wl_surface_commit(surf); + client_roundtrip(client); + + /* Try once more with old NULL buffer. */ + set_source(vp, 1200, 1200, 20, 10); + wl_surface_commit(surf); + client_roundtrip(client); + + /* When buffer comes back, source rect matters again. */ + wl_surface_attach(surf, client->surface->buffer->proxy, 0, 0); + wl_surface_commit(surf); + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_OUT_OF_BUFFER); +} + +TEST(test_viewporter_no_surface_set_source) +{ + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + vp = create_viewport(client); + wl_surface_destroy(client->surface->wl_surface); + client->surface->wl_surface = NULL; + + /* But the wl_surface does not exist anymore. */ + set_source(vp, 1000, 1000, 20, 10); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_NO_SURFACE); +} + +TEST(test_viewporter_no_surface_set_destination) +{ + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + vp = create_viewport(client); + wl_surface_destroy(client->surface->wl_surface); + client->surface->wl_surface = NULL; + + /* But the wl_surface does not exist anymore. */ + wp_viewport_set_destination(vp, 99, 99); + + expect_protocol_error(client, &wp_viewport_interface, + WP_VIEWPORT_ERROR_NO_SURFACE); +} + +TEST(test_viewporter_no_surface_destroy) +{ + struct client *client; + struct wp_viewport *vp; + + client = create_client_and_test_surface(100, 50, 123, 77); + vp = create_viewport(client); + wl_surface_destroy(client->surface->wl_surface); + client->surface->wl_surface = NULL; + + /* But the wl_surface does not exist anymore. */ + wp_viewport_destroy(vp); + + client_roundtrip(client); +} |