1*84e872a0SLloyd PiqueFrom 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2*84e872a0SLloyd PiqueFrom: Lloyd Pique <[email protected]>
3*84e872a0SLloyd PiqueDate: Fri, 11 Mar 2022 20:04:55 -0800
4*84e872a0SLloyd PiqueSubject: [PATCH 6/6] client: Log unknown messages through the observer API
5*84e872a0SLloyd Pique
6*84e872a0SLloyd PiqueClient message observers 6/6
7*84e872a0SLloyd Pique
8*84e872a0SLloyd PiqueWhen the client code receives an event message for an unknown (or zombie)
9*84e872a0SLloyd Piqueobject, the code was logging a message only to stderr, and only if debug_client
10*84e872a0SLloyd Piquewas set.
11*84e872a0SLloyd Pique
12*84e872a0SLloyd PiqueIntroduce a helper function to create some temporary wl_closure and related
13*84e872a0SLloyd Piquestructures so that the unknown message can be sent out using the new client
14*84e872a0SLloyd Piqueobserver API. This allows the client implementation to potentially log it
15*84e872a0SLloyd Piquesomewhere more useful than to just stderr, and it can register an observer at
16*84e872a0SLloyd Piqueany time too.
17*84e872a0SLloyd Pique
18*84e872a0SLloyd PiqueNote that the message that is logged is now structured slightly differently,
19*84e872a0SLloyd Piquethough it contains the same content.
20*84e872a0SLloyd Pique
21*84e872a0SLloyd PiqueSigned-off-by: Lloyd Pique <[email protected]>
22*84e872a0SLloyd Pique
23*84e872a0SLloyd Piquediff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
24*84e872a0SLloyd Piqueindex a57cbe0..af7c184 100644
25*84e872a0SLloyd Pique--- a/src/wayland-client-core.h
26*84e872a0SLloyd Pique+++ b/src/wayland-client-core.h
27*84e872a0SLloyd Pique@@ -311,6 +311,9 @@ enum wl_client_message_discarded_reason {
28*84e872a0SLloyd Pique
29*84e872a0SLloyd Pique 	/** The target had no listener or dispatcher */
30*84e872a0SLloyd Pique 	WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
31*84e872a0SLloyd Pique+
32*84e872a0SLloyd Pique+	/** The target was not valid when the event was demarshalled */
33*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
34*84e872a0SLloyd Pique };
35*84e872a0SLloyd Pique
36*84e872a0SLloyd Pique /**
37*84e872a0SLloyd Piquediff --git a/src/wayland-client.c b/src/wayland-client.c
38*84e872a0SLloyd Piqueindex ab68bdb..d54e715 100644
39*84e872a0SLloyd Pique--- a/src/wayland-client.c
40*84e872a0SLloyd Pique+++ b/src/wayland-client.c
41*84e872a0SLloyd Pique@@ -178,6 +178,8 @@ get_discarded_reason_str(
42*84e872a0SLloyd Pique 		return "dead proxy on dispatch";
43*84e872a0SLloyd Pique 	case WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH:
44*84e872a0SLloyd Pique 		return "no listener on dispatch";
45*84e872a0SLloyd Pique+	case WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL:
46*84e872a0SLloyd Pique+		return "unknown id on demarshal";
47*84e872a0SLloyd Pique 	}
48*84e872a0SLloyd Pique 	return NULL;
49*84e872a0SLloyd Pique }
50*84e872a0SLloyd Pique@@ -237,6 +239,53 @@ closure_log(struct wl_closure *closure, struct wl_proxy *proxy, bool send,
51*84e872a0SLloyd Pique 	}
52*84e872a0SLloyd Pique }
53*84e872a0SLloyd Pique
54*84e872a0SLloyd Pique+/**
55*84e872a0SLloyd Pique+ * This function helps log unknown messages on the client, when logging is
56*84e872a0SLloyd Pique+ * enabled.
57*84e872a0SLloyd Pique+ *
58*84e872a0SLloyd Pique+ * \param display    current display
59*84e872a0SLloyd Pique+ * \param zombie     true if there was a zombie for the message target
60*84e872a0SLloyd Pique+ * \param id         id of the proxy this message was meant for
61*84e872a0SLloyd Pique+ * \param opcode     opcode from the message
62*84e872a0SLloyd Pique+ * \param num_fds    number of fd arguments for this message
63*84e872a0SLloyd Pique+ * \param num_bytes  byte size of this message
64*84e872a0SLloyd Pique+ */
65*84e872a0SLloyd Pique+static void
66*84e872a0SLloyd Pique+log_unknown_message(struct wl_display *display, bool zombie, uint32_t id,
67*84e872a0SLloyd Pique+		    int opcode, int num_fds, int num_bytes)
68*84e872a0SLloyd Pique+{
69*84e872a0SLloyd Pique+	char event_detail[100];
70*84e872a0SLloyd Pique+	struct wl_interface unknown_interface = { 0 };
71*84e872a0SLloyd Pique+	struct wl_proxy unknown_proxy = { 0 };
72*84e872a0SLloyd Pique+	struct wl_message unknown_message = { 0 };
73*84e872a0SLloyd Pique+	struct wl_closure unknown_closure = { 0 };
74*84e872a0SLloyd Pique+
75*84e872a0SLloyd Pique+	if (!debug_client && wl_list_empty(&display->observers))
76*84e872a0SLloyd Pique+		return;
77*84e872a0SLloyd Pique+
78*84e872a0SLloyd Pique+	snprintf(event_detail, sizeof event_detail,
79*84e872a0SLloyd Pique+		 "[event %d, %d fds, %d bytes]", opcode, num_fds, num_bytes);
80*84e872a0SLloyd Pique+
81*84e872a0SLloyd Pique+	unknown_interface.name = zombie ? "[zombie]" : "[unknown]";
82*84e872a0SLloyd Pique+
83*84e872a0SLloyd Pique+	unknown_proxy.object.interface = &unknown_interface;
84*84e872a0SLloyd Pique+	unknown_proxy.object.id = id;
85*84e872a0SLloyd Pique+	unknown_proxy.display = display;
86*84e872a0SLloyd Pique+	unknown_proxy.refcount = -1;
87*84e872a0SLloyd Pique+	unknown_proxy.flags = WL_PROXY_FLAG_WRAPPER;
88*84e872a0SLloyd Pique+
89*84e872a0SLloyd Pique+	unknown_message.name = event_detail;
90*84e872a0SLloyd Pique+	unknown_message.signature = "";
91*84e872a0SLloyd Pique+	unknown_message.types = NULL;
92*84e872a0SLloyd Pique+
93*84e872a0SLloyd Pique+	unknown_closure.message = &unknown_message;
94*84e872a0SLloyd Pique+	unknown_closure.opcode = opcode;
95*84e872a0SLloyd Pique+	unknown_closure.proxy = &unknown_proxy;
96*84e872a0SLloyd Pique+
97*84e872a0SLloyd Pique+	closure_log(&unknown_closure, &unknown_proxy, false,
98*84e872a0SLloyd Pique+		    WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL);
99*84e872a0SLloyd Pique+}
100*84e872a0SLloyd Pique+
101*84e872a0SLloyd Pique /**
102*84e872a0SLloyd Pique  * This helper function wakes up all threads that are
103*84e872a0SLloyd Pique  * waiting for display->reader_cond (i. e. when reading is done,
104*84e872a0SLloyd Pique@@ -1626,8 +1675,6 @@ queue_event(struct wl_display *display, int len)
105*84e872a0SLloyd Pique 	struct wl_closure *closure;
106*84e872a0SLloyd Pique 	const struct wl_message *message;
107*84e872a0SLloyd Pique 	struct wl_event_queue *queue;
108*84e872a0SLloyd Pique-	struct timespec tp;
109*84e872a0SLloyd Pique-	unsigned int time;
110*84e872a0SLloyd Pique 	int num_zombie_fds;
111*84e872a0SLloyd Pique
112*84e872a0SLloyd Pique 	wl_connection_copy(display->connection, p, sizeof p);
113*84e872a0SLloyd Pique@@ -1645,17 +1692,9 @@ queue_event(struct wl_display *display, int len)
114*84e872a0SLloyd Pique 		num_zombie_fds = (zombie && opcode < zombie->event_count) ?
115*84e872a0SLloyd Pique 			zombie->fd_count[opcode] : 0;
116*84e872a0SLloyd Pique
117*84e872a0SLloyd Pique-		if (debug_client) {
118*84e872a0SLloyd Pique-			clock_gettime(CLOCK_REALTIME, &tp);
119*84e872a0SLloyd Pique-			time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
120*84e872a0SLloyd Pique+		log_unknown_message(display, !!zombie, id, opcode,
121*84e872a0SLloyd Pique+				    num_zombie_fds, size);
122*84e872a0SLloyd Pique
123*84e872a0SLloyd Pique-			fprintf(stderr, "[%7u.%03u] discarded [%s]@%d.[event %d]"
124*84e872a0SLloyd Pique-				"(%d fd, %d byte)\n",
125*84e872a0SLloyd Pique-				time / 1000, time % 1000,
126*84e872a0SLloyd Pique-				zombie ? "zombie" : "unknown",
127*84e872a0SLloyd Pique-				id, opcode,
128*84e872a0SLloyd Pique-				num_zombie_fds, size);
129*84e872a0SLloyd Pique-		}
130*84e872a0SLloyd Pique 		if (num_zombie_fds > 0)
131*84e872a0SLloyd Pique 			wl_connection_close_fds_in(display->connection,
132*84e872a0SLloyd Pique 						   num_zombie_fds);
133*84e872a0SLloyd Piquediff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c
134*84e872a0SLloyd Piqueindex 9420b5e..94e437d 100644
135*84e872a0SLloyd Pique--- a/tests/protocol-logger-test.c
136*84e872a0SLloyd Pique+++ b/tests/protocol-logger-test.c
137*84e872a0SLloyd Pique@@ -562,3 +562,250 @@ TEST(client_discards_if_no_listener_on_dispatch)
138*84e872a0SLloyd Pique
139*84e872a0SLloyd Pique 	logger_teardown(&compositor, &client);
140*84e872a0SLloyd Pique }
141*84e872a0SLloyd Pique+
142*84e872a0SLloyd Pique+TEST(client_discards_if_invalid_id_on_demarshal)
143*84e872a0SLloyd Pique+{
144*84e872a0SLloyd Pique+	test_set_timeout(1);
145*84e872a0SLloyd Pique+
146*84e872a0SLloyd Pique+	struct expected_client_message client_messages[] = {
147*84e872a0SLloyd Pique+		{
148*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
149*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
150*84e872a0SLloyd Pique+			.class = "wl_display",
151*84e872a0SLloyd Pique+			.opcode = 0,
152*84e872a0SLloyd Pique+			.message_name = "sync",
153*84e872a0SLloyd Pique+			.args_count = 1,
154*84e872a0SLloyd Pique+		},
155*84e872a0SLloyd Pique+		{
156*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
157*84e872a0SLloyd Pique+			.discarded_reason =
158*84e872a0SLloyd Pique+				WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
159*84e872a0SLloyd Pique+			.class = "[unknown]",
160*84e872a0SLloyd Pique+			.opcode = 0,
161*84e872a0SLloyd Pique+			.message_name = "[event 0, 0 fds, 12 bytes]",
162*84e872a0SLloyd Pique+			.args_count = 0,
163*84e872a0SLloyd Pique+		},
164*84e872a0SLloyd Pique+		{
165*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
166*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
167*84e872a0SLloyd Pique+			.class = "wl_display",
168*84e872a0SLloyd Pique+			.opcode = 1,
169*84e872a0SLloyd Pique+			.message_name = "delete_id",
170*84e872a0SLloyd Pique+			.args_count = 1,
171*84e872a0SLloyd Pique+		},
172*84e872a0SLloyd Pique+	};
173*84e872a0SLloyd Pique+	struct compositor compositor = { 0 };
174*84e872a0SLloyd Pique+	struct client client = { 0 };
175*84e872a0SLloyd Pique+
176*84e872a0SLloyd Pique+	logger_setup(&compositor, &client);
177*84e872a0SLloyd Pique+
178*84e872a0SLloyd Pique+	compositor.expected_msg_count = 3;
179*84e872a0SLloyd Pique+
180*84e872a0SLloyd Pique+	client.expected_msg = &client_messages[0];
181*84e872a0SLloyd Pique+	client.expected_msg_count = ARRAY_LENGTH(client_messages);
182*84e872a0SLloyd Pique+
183*84e872a0SLloyd Pique+	client.cb = wl_display_sync(client.display);
184*84e872a0SLloyd Pique+	wl_display_flush(client.display);
185*84e872a0SLloyd Pique+
186*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
187*84e872a0SLloyd Pique+		wl_event_loop_dispatch(compositor.loop, -1);
188*84e872a0SLloyd Pique+		wl_display_flush_clients(compositor.display);
189*84e872a0SLloyd Pique+	}
190*84e872a0SLloyd Pique+
191*84e872a0SLloyd Pique+	// To get a WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, we
192*84e872a0SLloyd Pique+	// destroy the callback before reading and dispatching client events.
193*84e872a0SLloyd Pique+	wl_callback_destroy(client.cb);
194*84e872a0SLloyd Pique+
195*84e872a0SLloyd Pique+	while (client.actual_msg_count < client.expected_msg_count) {
196*84e872a0SLloyd Pique+		wl_display_dispatch(client.display);
197*84e872a0SLloyd Pique+	}
198*84e872a0SLloyd Pique+
199*84e872a0SLloyd Pique+	logger_teardown(&compositor, &client);
200*84e872a0SLloyd Pique+}
201*84e872a0SLloyd Pique+
202*84e872a0SLloyd Pique+static const struct wl_keyboard_interface keyboard_interface = { 0 };
203*84e872a0SLloyd Pique+
204*84e872a0SLloyd Pique+static void
205*84e872a0SLloyd Pique+seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
206*84e872a0SLloyd Pique+		 uint32_t id)
207*84e872a0SLloyd Pique+{
208*84e872a0SLloyd Pique+	assert(false && "Not expected to be called by client.");
209*84e872a0SLloyd Pique+}
210*84e872a0SLloyd Pique+
211*84e872a0SLloyd Pique+static void
212*84e872a0SLloyd Pique+seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
213*84e872a0SLloyd Pique+		  uint32_t id)
214*84e872a0SLloyd Pique+{
215*84e872a0SLloyd Pique+	struct wl_resource *keyboard_res;
216*84e872a0SLloyd Pique+
217*84e872a0SLloyd Pique+	keyboard_res =
218*84e872a0SLloyd Pique+		wl_resource_create(client, &wl_keyboard_interface,
219*84e872a0SLloyd Pique+				   wl_resource_get_version(resource), id);
220*84e872a0SLloyd Pique+	wl_resource_set_implementation(keyboard_res, &keyboard_interface, NULL,
221*84e872a0SLloyd Pique+				       NULL);
222*84e872a0SLloyd Pique+
223*84e872a0SLloyd Pique+	wl_keyboard_send_key(keyboard_res, 0, 0, 0, 0);
224*84e872a0SLloyd Pique+}
225*84e872a0SLloyd Pique+
226*84e872a0SLloyd Pique+static void
227*84e872a0SLloyd Pique+seat_get_touch(struct wl_client *client, struct wl_resource *resource,
228*84e872a0SLloyd Pique+	       uint32_t id)
229*84e872a0SLloyd Pique+{
230*84e872a0SLloyd Pique+	assert(false && "Not expected to be called by client.");
231*84e872a0SLloyd Pique+}
232*84e872a0SLloyd Pique+
233*84e872a0SLloyd Pique+static void
234*84e872a0SLloyd Pique+seat_release(struct wl_client *client, struct wl_resource *resource)
235*84e872a0SLloyd Pique+{
236*84e872a0SLloyd Pique+	wl_resource_destroy(resource);
237*84e872a0SLloyd Pique+}
238*84e872a0SLloyd Pique+
239*84e872a0SLloyd Pique+static const struct wl_seat_interface seat_interface = {
240*84e872a0SLloyd Pique+	&seat_get_pointer,
241*84e872a0SLloyd Pique+	&seat_get_keyboard,
242*84e872a0SLloyd Pique+	&seat_get_touch,
243*84e872a0SLloyd Pique+	&seat_release,
244*84e872a0SLloyd Pique+};
245*84e872a0SLloyd Pique+
246*84e872a0SLloyd Pique+static void
247*84e872a0SLloyd Pique+bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id)
248*84e872a0SLloyd Pique+{
249*84e872a0SLloyd Pique+	struct wl_resource *seat_res;
250*84e872a0SLloyd Pique+
251*84e872a0SLloyd Pique+	seat_res = wl_resource_create(client, &wl_seat_interface, vers, id);
252*84e872a0SLloyd Pique+	wl_resource_set_implementation(seat_res, &seat_interface, NULL, NULL);
253*84e872a0SLloyd Pique+}
254*84e872a0SLloyd Pique+
255*84e872a0SLloyd Pique+static void
256*84e872a0SLloyd Pique+registry_seat_listener_handle_global(void *data, struct wl_registry *registry,
257*84e872a0SLloyd Pique+				     uint32_t id, const char *intf,
258*84e872a0SLloyd Pique+				     uint32_t ver)
259*84e872a0SLloyd Pique+{
260*84e872a0SLloyd Pique+	uint32_t *seat_id_ptr = data;
261*84e872a0SLloyd Pique+
262*84e872a0SLloyd Pique+	if (strcmp(intf, wl_seat_interface.name) == 0) {
263*84e872a0SLloyd Pique+		*seat_id_ptr = id;
264*84e872a0SLloyd Pique+	}
265*84e872a0SLloyd Pique+}
266*84e872a0SLloyd Pique+
267*84e872a0SLloyd Pique+static const struct wl_registry_listener registry_seat_listener = {
268*84e872a0SLloyd Pique+	registry_seat_listener_handle_global, NULL
269*84e872a0SLloyd Pique+};
270*84e872a0SLloyd Pique+
271*84e872a0SLloyd Pique+TEST(client_discards_if_zombie_on_demarshal)
272*84e872a0SLloyd Pique+{
273*84e872a0SLloyd Pique+	test_set_timeout(1);
274*84e872a0SLloyd Pique+
275*84e872a0SLloyd Pique+	struct expected_client_message client_messages[] = {
276*84e872a0SLloyd Pique+		{
277*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
278*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
279*84e872a0SLloyd Pique+			.class = "wl_display",
280*84e872a0SLloyd Pique+			.opcode = 1,
281*84e872a0SLloyd Pique+			.message_name = "get_registry",
282*84e872a0SLloyd Pique+			.args_count = 1,
283*84e872a0SLloyd Pique+		},
284*84e872a0SLloyd Pique+		{
285*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
286*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
287*84e872a0SLloyd Pique+			.class = "wl_registry",
288*84e872a0SLloyd Pique+			.opcode = 0,
289*84e872a0SLloyd Pique+			.message_name = "global",
290*84e872a0SLloyd Pique+			.args_count = 3,
291*84e872a0SLloyd Pique+		},
292*84e872a0SLloyd Pique+		{
293*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
294*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
295*84e872a0SLloyd Pique+			.class = "wl_registry",
296*84e872a0SLloyd Pique+			.opcode = 0,
297*84e872a0SLloyd Pique+			.message_name = "bind",
298*84e872a0SLloyd Pique+			.args_count = 4,
299*84e872a0SLloyd Pique+		},
300*84e872a0SLloyd Pique+		{
301*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
302*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
303*84e872a0SLloyd Pique+			.class = "wl_seat",
304*84e872a0SLloyd Pique+			.opcode = 1,
305*84e872a0SLloyd Pique+			.message_name = "get_keyboard",
306*84e872a0SLloyd Pique+			.args_count = 1,
307*84e872a0SLloyd Pique+		},
308*84e872a0SLloyd Pique+		{
309*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
310*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
311*84e872a0SLloyd Pique+			.class = "wl_keyboard",
312*84e872a0SLloyd Pique+			.opcode = 0,
313*84e872a0SLloyd Pique+			.message_name = "release",
314*84e872a0SLloyd Pique+			.args_count = 0,
315*84e872a0SLloyd Pique+		},
316*84e872a0SLloyd Pique+		{
317*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
318*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
319*84e872a0SLloyd Pique+			.class = "wl_seat",
320*84e872a0SLloyd Pique+			.opcode = 3,
321*84e872a0SLloyd Pique+			.message_name = "release",
322*84e872a0SLloyd Pique+			.args_count = 0,
323*84e872a0SLloyd Pique+		},
324*84e872a0SLloyd Pique+		{
325*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
326*84e872a0SLloyd Pique+			.discarded_reason =
327*84e872a0SLloyd Pique+				WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL,
328*84e872a0SLloyd Pique+			.class = "[zombie]",
329*84e872a0SLloyd Pique+			.opcode = 3,
330*84e872a0SLloyd Pique+			.message_name = "[event 3, 0 fds, 24 bytes]",
331*84e872a0SLloyd Pique+			.args_count = 0,
332*84e872a0SLloyd Pique+		},
333*84e872a0SLloyd Pique+	};
334*84e872a0SLloyd Pique+
335*84e872a0SLloyd Pique+	struct compositor compositor = { 0 };
336*84e872a0SLloyd Pique+	struct client client = { 0 };
337*84e872a0SLloyd Pique+	struct wl_global *g_keyboard;
338*84e872a0SLloyd Pique+	struct wl_registry *registry;
339*84e872a0SLloyd Pique+	struct wl_seat *seat;
340*84e872a0SLloyd Pique+	struct wl_keyboard *keyboard;
341*84e872a0SLloyd Pique+	int32_t seat_id;
342*84e872a0SLloyd Pique+
343*84e872a0SLloyd Pique+	logger_setup(&compositor, &client);
344*84e872a0SLloyd Pique+
345*84e872a0SLloyd Pique+	client.expected_msg = &client_messages[0];
346*84e872a0SLloyd Pique+	client.expected_msg_count = ARRAY_LENGTH(client_messages);
347*84e872a0SLloyd Pique+
348*84e872a0SLloyd Pique+	g_keyboard = wl_global_create(compositor.display, &wl_seat_interface,
349*84e872a0SLloyd Pique+				      5, &compositor.display, bind_seat);
350*84e872a0SLloyd Pique+
351*84e872a0SLloyd Pique+	registry = wl_display_get_registry(client.display);
352*84e872a0SLloyd Pique+	wl_registry_add_listener(registry, &registry_seat_listener, &seat_id);
353*84e872a0SLloyd Pique+	wl_display_flush(client.display);
354*84e872a0SLloyd Pique+
355*84e872a0SLloyd Pique+	compositor.actual_msg_count = 0;
356*84e872a0SLloyd Pique+	compositor.expected_msg_count = 2;
357*84e872a0SLloyd Pique+
358*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
359*84e872a0SLloyd Pique+		wl_event_loop_dispatch(compositor.loop, -1);
360*84e872a0SLloyd Pique+		wl_display_flush_clients(compositor.display);
361*84e872a0SLloyd Pique+	}
362*84e872a0SLloyd Pique+
363*84e872a0SLloyd Pique+	wl_display_dispatch(client.display);
364*84e872a0SLloyd Pique+
365*84e872a0SLloyd Pique+	seat = wl_registry_bind(registry, seat_id, &wl_seat_interface, 5);
366*84e872a0SLloyd Pique+	keyboard = wl_seat_get_keyboard(seat);
367*84e872a0SLloyd Pique+	wl_display_flush(client.display);
368*84e872a0SLloyd Pique+
369*84e872a0SLloyd Pique+	compositor.actual_msg_count = 0;
370*84e872a0SLloyd Pique+	compositor.expected_msg_count = 3;
371*84e872a0SLloyd Pique+
372*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
373*84e872a0SLloyd Pique+		wl_event_loop_dispatch(compositor.loop, -1);
374*84e872a0SLloyd Pique+		wl_display_flush_clients(compositor.display);
375*84e872a0SLloyd Pique+	}
376*84e872a0SLloyd Pique+
377*84e872a0SLloyd Pique+	wl_keyboard_release(keyboard);
378*84e872a0SLloyd Pique+	wl_seat_release(seat);
379*84e872a0SLloyd Pique+
380*84e872a0SLloyd Pique+	wl_display_dispatch(client.display);
381*84e872a0SLloyd Pique+
382*84e872a0SLloyd Pique+	wl_registry_destroy(registry);
383*84e872a0SLloyd Pique+
384*84e872a0SLloyd Pique+	wl_global_destroy(g_keyboard);
385*84e872a0SLloyd Pique+
386*84e872a0SLloyd Pique+	logger_teardown(&compositor, &client);
387*84e872a0SLloyd Pique+}
388