xref: /aosp_15_r20/external/wayland/patches/0002-client-Add-message-observer-interface.diff (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
1*84e872a0SLloyd PiqueFrom 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2*84e872a0SLloyd PiqueFrom: Lloyd Pique <[email protected]>
3*84e872a0SLloyd PiqueDate: Thu, 10 Mar 2022 17:44:32 -0800
4*84e872a0SLloyd PiqueSubject: [PATCH 2/6] client: Add message observer interface
5*84e872a0SLloyd Pique
6*84e872a0SLloyd PiqueClient message observers 2/6
7*84e872a0SLloyd Pique
8*84e872a0SLloyd PiqueIntroduce a client message observer interface, strongly resembling the server
9*84e872a0SLloyd Piqueprotocol logger interface added in commit 450f06e2.
10*84e872a0SLloyd Pique
11*84e872a0SLloyd PiqueThis means a new pair of public API functions:
12*84e872a0SLloyd Pique
13*84e872a0SLloyd Pique* wl_display_create_client_observer(): allows a client to register an observer
14*84e872a0SLloyd Pique  function, which is called for messages that are received or sent.
15*84e872a0SLloyd Pique
16*84e872a0SLloyd Pique* wl_client_observer_destroy() which destroys the observer created by the prior
17*84e872a0SLloyd Pique  function.
18*84e872a0SLloyd Pique
19*84e872a0SLloyd PiqueWith these changes, a client can set and clear an observer at run-time, and can
20*84e872a0SLloyd Piqueuse it to log client messages to a location other than stderr.
21*84e872a0SLloyd Pique
22*84e872a0SLloyd PiqueThe existing protocol-logger-test has also been revised and extended to demonstrate
23*84e872a0SLloyd Piqueusing the new API for test use, to validate the sequence of messages sent and
24*84e872a0SLloyd Piquereceived by the client, on top of the existing checks to do the same for the
25*84e872a0SLloyd Piqueserver messages.
26*84e872a0SLloyd Pique
27*84e872a0SLloyd PiqueSigned-off-by: Lloyd Pique <[email protected]>
28*84e872a0SLloyd Pique
29*84e872a0SLloyd Piquediff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
30*84e872a0SLloyd Piqueindex ce91a6f..2aa72a4 100644
31*84e872a0SLloyd Pique--- a/src/wayland-client-core.h
32*84e872a0SLloyd Pique+++ b/src/wayland-client-core.h
33*84e872a0SLloyd Pique@@ -285,6 +285,104 @@ wl_display_read_events(struct wl_display *display);
34*84e872a0SLloyd Pique void
35*84e872a0SLloyd Pique wl_log_set_handler_client(wl_log_func_t handler);
36*84e872a0SLloyd Pique
37*84e872a0SLloyd Pique+/**
38*84e872a0SLloyd Pique+ * The message type.
39*84e872a0SLloyd Pique+ */
40*84e872a0SLloyd Pique+enum wl_client_message_type {
41*84e872a0SLloyd Pique+	/** The message is a request */
42*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_REQUEST,
43*84e872a0SLloyd Pique+
44*84e872a0SLloyd Pique+	/** The message is an event */
45*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_EVENT,
46*84e872a0SLloyd Pique+};
47*84e872a0SLloyd Pique+
48*84e872a0SLloyd Pique+/**
49*84e872a0SLloyd Pique+ * The message discard reason codes.
50*84e872a0SLloyd Pique+ */
51*84e872a0SLloyd Pique+enum wl_client_message_discarded_reason {
52*84e872a0SLloyd Pique+	/** The message was handled normally, and not discarded. */
53*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_NOT_DISCARDED = 0,
54*84e872a0SLloyd Pique+
55*84e872a0SLloyd Pique+	/** The target was not alive at dispatch time */
56*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,
57*84e872a0SLloyd Pique+
58*84e872a0SLloyd Pique+	/** The target had no listener or dispatcher */
59*84e872a0SLloyd Pique+	WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
60*84e872a0SLloyd Pique+};
61*84e872a0SLloyd Pique+
62*84e872a0SLloyd Pique+/**
63*84e872a0SLloyd Pique+ * The structure used to communicate details about an observed message to the
64*84e872a0SLloyd Pique+ * registered observers.
65*84e872a0SLloyd Pique+ */
66*84e872a0SLloyd Pique+struct wl_client_observed_message {
67*84e872a0SLloyd Pique+	/** The target for the message */
68*84e872a0SLloyd Pique+	struct wl_proxy *proxy;
69*84e872a0SLloyd Pique+
70*84e872a0SLloyd Pique+	/** The message opcode */
71*84e872a0SLloyd Pique+	int message_opcode;
72*84e872a0SLloyd Pique+
73*84e872a0SLloyd Pique+	/** The protocol message structure */
74*84e872a0SLloyd Pique+	const struct wl_message *message;
75*84e872a0SLloyd Pique+
76*84e872a0SLloyd Pique+	/** The count of arguments to the message */
77*84e872a0SLloyd Pique+	int arguments_count;
78*84e872a0SLloyd Pique+
79*84e872a0SLloyd Pique+	/** The argument array for the messagge */
80*84e872a0SLloyd Pique+	const union wl_argument *arguments;
81*84e872a0SLloyd Pique+
82*84e872a0SLloyd Pique+	/** The discard reason code */
83*84e872a0SLloyd Pique+	enum wl_client_message_discarded_reason discarded_reason;
84*84e872a0SLloyd Pique+
85*84e872a0SLloyd Pique+	/**
86*84e872a0SLloyd Pique+	 * The discard reason string, or NULL if the event was not discarded.
87*84e872a0SLloyd Pique+	 *
88*84e872a0SLloyd Pique+	 * This string is only for convenience for a observer that does
89*84e872a0SLloyd Pique+	 * logging. The string values should not be considered stable, and
90*84e872a0SLloyd Pique+	 * are not localized.
91*84e872a0SLloyd Pique+	 */
92*84e872a0SLloyd Pique+	const char *discarded_reason_str;
93*84e872a0SLloyd Pique+};
94*84e872a0SLloyd Pique+
95*84e872a0SLloyd Pique+/**
96*84e872a0SLloyd Pique+ * The signature for a client message observer function, as registered with
97*84e872a0SLloyd Pique+ * wl_display_add_client_observer().
98*84e872a0SLloyd Pique+ *
99*84e872a0SLloyd Pique+ * \param user_data \c user_data pointer given when the observer was
100*84e872a0SLloyd Pique+ *                  registered with \c wl_display_create_client_observer
101*84e872a0SLloyd Pique+ * \param type      type of message
102*84e872a0SLloyd Pique+ * \param message   details for the message
103*84e872a0SLloyd Pique+ */
104*84e872a0SLloyd Pique+typedef void (*wl_client_message_observer_func_t)(
105*84e872a0SLloyd Pique+	void *user_data, enum wl_client_message_type type,
106*84e872a0SLloyd Pique+	const struct wl_client_observed_message *message);
107*84e872a0SLloyd Pique+
108*84e872a0SLloyd Pique+/** \class wl_client_observer
109*84e872a0SLloyd Pique+ *
110*84e872a0SLloyd Pique+ * \brief Represents a client message observer
111*84e872a0SLloyd Pique+ *
112*84e872a0SLloyd Pique+ * A client observer allows the client to observe all request and event
113*84e872a0SLloyd Pique+ * message traffic to and from the client. For events, the observer is
114*84e872a0SLloyd Pique+ * also given a discard reason if the event wasn't handled.
115*84e872a0SLloyd Pique+ *
116*84e872a0SLloyd Pique+ * The typical use for the observer is to allow the client implementation to
117*84e872a0SLloyd Pique+ * do its own debug logging, as the default when setting WAYLAND_DEBUG is to
118*84e872a0SLloyd Pique+ * log to stderr.
119*84e872a0SLloyd Pique+ *
120*84e872a0SLloyd Pique+ * With this runtime call, the client can also enable and disable the observer
121*84e872a0SLloyd Pique+ * at any time.
122*84e872a0SLloyd Pique+ *
123*84e872a0SLloyd Pique+ * The protocol-logger-test.c file has an example of a logger implementation.
124*84e872a0SLloyd Pique+ */
125*84e872a0SLloyd Pique+struct wl_client_observer;
126*84e872a0SLloyd Pique+
127*84e872a0SLloyd Pique+struct wl_client_observer *
128*84e872a0SLloyd Pique+wl_display_create_client_observer(struct wl_display *display,
129*84e872a0SLloyd Pique+				  wl_client_message_observer_func_t observer,
130*84e872a0SLloyd Pique+				  void *user_data);
131*84e872a0SLloyd Pique+
132*84e872a0SLloyd Pique+void
133*84e872a0SLloyd Pique+wl_client_observer_destroy(struct wl_client_observer *observer);
134*84e872a0SLloyd Pique+
135*84e872a0SLloyd Pique #ifdef  __cplusplus
136*84e872a0SLloyd Pique }
137*84e872a0SLloyd Pique #endif
138*84e872a0SLloyd Piquediff --git a/src/wayland-client.c b/src/wayland-client.c
139*84e872a0SLloyd Piqueindex ae47307..04b4f60 100644
140*84e872a0SLloyd Pique--- a/src/wayland-client.c
141*84e872a0SLloyd Pique+++ b/src/wayland-client.c
142*84e872a0SLloyd Pique@@ -109,10 +109,19 @@ struct wl_display {
143*84e872a0SLloyd Pique 	int reader_count;
144*84e872a0SLloyd Pique 	uint32_t read_serial;
145*84e872a0SLloyd Pique 	pthread_cond_t reader_cond;
146*84e872a0SLloyd Pique+
147*84e872a0SLloyd Pique+	struct wl_list observers;
148*84e872a0SLloyd Pique };
149*84e872a0SLloyd Pique
150*84e872a0SLloyd Pique /** \endcond */
151*84e872a0SLloyd Pique
152*84e872a0SLloyd Pique+struct wl_client_observer {
153*84e872a0SLloyd Pique+	struct wl_list link;
154*84e872a0SLloyd Pique+	struct wl_display *display;
155*84e872a0SLloyd Pique+	wl_client_message_observer_func_t func;
156*84e872a0SLloyd Pique+	void *user_data;
157*84e872a0SLloyd Pique+};
158*84e872a0SLloyd Pique+
159*84e872a0SLloyd Pique static int debug_client = 0;
160*84e872a0SLloyd Pique
161*84e872a0SLloyd Pique /**
162*84e872a0SLloyd Pique@@ -151,6 +160,28 @@ adjust_closure_args_for_logging(struct wl_closure *closure, bool send)
163*84e872a0SLloyd Pique 	}
164*84e872a0SLloyd Pique }
165*84e872a0SLloyd Pique
166*84e872a0SLloyd Pique+/**
167*84e872a0SLloyd Pique+ * Maps the \c discard_reason to a string suitable for logging.
168*84e872a0SLloyd Pique+ *
169*84e872a0SLloyd Pique+ * \param discarded_reason  reason for discard
170*84e872a0SLloyd Pique+ * \return A string describing the reason, or NULL.
171*84e872a0SLloyd Pique+ *
172*84e872a0SLloyd Pique+ */
173*84e872a0SLloyd Pique+static const char *
174*84e872a0SLloyd Pique+get_discarded_reason_str(
175*84e872a0SLloyd Pique+	enum wl_client_message_discarded_reason discarded_reason)
176*84e872a0SLloyd Pique+{
177*84e872a0SLloyd Pique+	switch (discarded_reason) {
178*84e872a0SLloyd Pique+	case WL_CLIENT_MESSAGE_NOT_DISCARDED:
179*84e872a0SLloyd Pique+		return NULL;
180*84e872a0SLloyd Pique+	case WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH:
181*84e872a0SLloyd Pique+		return "dead proxy on dispatch";
182*84e872a0SLloyd Pique+	case WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH:
183*84e872a0SLloyd Pique+		return "no listener on dispatch";
184*84e872a0SLloyd Pique+	}
185*84e872a0SLloyd Pique+	return NULL;
186*84e872a0SLloyd Pique+}
187*84e872a0SLloyd Pique+
188*84e872a0SLloyd Pique /**
189*84e872a0SLloyd Pique  * This function helps log closures from the client, assuming logging is
190*84e872a0SLloyd Pique  * enabled.
191*84e872a0SLloyd Pique@@ -158,16 +189,18 @@ adjust_closure_args_for_logging(struct wl_closure *closure, bool send)
192*84e872a0SLloyd Pique  * \param closure    closure for the message
193*84e872a0SLloyd Pique  * \param proxy      proxy for the message
194*84e872a0SLloyd Pique  * \param send       true if this is closure is for a request
195*84e872a0SLloyd Pique- * \param discarded  true if this is message is being discarded
196*84e872a0SLloyd Pique- *
197*84e872a0SLloyd Pique+ * \param discarded_reason  reason if the message is being discarded, or
198*84e872a0SLloyd Pique+ *                          WL_CLIENT_MESSAGE_NOT_DISCARDED
199*84e872a0SLloyd Pique  */
200*84e872a0SLloyd Pique static void
201*84e872a0SLloyd Pique closure_log(struct wl_closure *closure, struct wl_proxy *proxy, bool send,
202*84e872a0SLloyd Pique-	    bool discarded)
203*84e872a0SLloyd Pique+	    enum wl_client_message_discarded_reason discarded_reason)
204*84e872a0SLloyd Pique {
205*84e872a0SLloyd Pique+	struct wl_display *display = proxy->display;
206*84e872a0SLloyd Pique+	const char *discarded_reason_str;
207*84e872a0SLloyd Pique 	struct wl_closure adjusted_closure = { 0 };
208*84e872a0SLloyd Pique
209*84e872a0SLloyd Pique-	if (!debug_client)
210*84e872a0SLloyd Pique+	if (!debug_client && wl_list_empty(&display->observers))
211*84e872a0SLloyd Pique 		return;
212*84e872a0SLloyd Pique
213*84e872a0SLloyd Pique 	// Note: The real closure has extra data (referenced by its args
214*84e872a0SLloyd Pique@@ -178,8 +211,30 @@ closure_log(struct wl_closure *closure, struct wl_proxy *proxy, bool send,
215*84e872a0SLloyd Pique 	// Adjust the closure arguments.
216*84e872a0SLloyd Pique 	adjust_closure_args_for_logging(&adjusted_closure, send);
217*84e872a0SLloyd Pique
218*84e872a0SLloyd Pique-	wl_closure_print(&adjusted_closure, &proxy->object, send,
219*84e872a0SLloyd Pique-			 discarded ? "" : NULL);
220*84e872a0SLloyd Pique+	discarded_reason_str = get_discarded_reason_str(discarded_reason);
221*84e872a0SLloyd Pique+
222*84e872a0SLloyd Pique+	if (debug_client)
223*84e872a0SLloyd Pique+		wl_closure_print(&adjusted_closure, &proxy->object, send,
224*84e872a0SLloyd Pique+				 discarded_reason_str);
225*84e872a0SLloyd Pique+
226*84e872a0SLloyd Pique+	if (!wl_list_empty(&display->observers)) {
227*84e872a0SLloyd Pique+		enum wl_client_message_type type =
228*84e872a0SLloyd Pique+			send ? WL_CLIENT_MESSAGE_REQUEST
229*84e872a0SLloyd Pique+			     : WL_CLIENT_MESSAGE_EVENT;
230*84e872a0SLloyd Pique+		struct wl_client_observer *observer;
231*84e872a0SLloyd Pique+		struct wl_client_observed_message message;
232*84e872a0SLloyd Pique+
233*84e872a0SLloyd Pique+		message.proxy = proxy;
234*84e872a0SLloyd Pique+		message.message_opcode = adjusted_closure.opcode;
235*84e872a0SLloyd Pique+		message.message = adjusted_closure.message;
236*84e872a0SLloyd Pique+		message.arguments_count = adjusted_closure.count;
237*84e872a0SLloyd Pique+		message.arguments = adjusted_closure.args;
238*84e872a0SLloyd Pique+		message.discarded_reason = discarded_reason;
239*84e872a0SLloyd Pique+		message.discarded_reason_str = discarded_reason_str;
240*84e872a0SLloyd Pique+		wl_list_for_each(observer, &display->observers, link) {
241*84e872a0SLloyd Pique+			observer->func(observer->user_data, type, &message);
242*84e872a0SLloyd Pique+		}
243*84e872a0SLloyd Pique+	}
244*84e872a0SLloyd Pique }
245*84e872a0SLloyd Pique
246*84e872a0SLloyd Pique /**
247*84e872a0SLloyd Pique@@ -952,7 +1007,7 @@ wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
248*84e872a0SLloyd Pique 		goto err_unlock;
249*84e872a0SLloyd Pique 	}
250*84e872a0SLloyd Pique
251*84e872a0SLloyd Pique-	closure_log(closure, proxy, true, false);
252*84e872a0SLloyd Pique+	closure_log(closure, proxy, true, WL_CLIENT_MESSAGE_NOT_DISCARDED);
253*84e872a0SLloyd Pique
254*84e872a0SLloyd Pique 	if (wl_closure_send(closure, proxy->display->connection)) {
255*84e872a0SLloyd Pique 		wl_log("Error sending request: %s\n", strerror(errno));
256*84e872a0SLloyd Pique@@ -1259,6 +1314,7 @@ wl_display_connect_to_fd(int fd)
257*84e872a0SLloyd Pique 	pthread_mutex_init(&display->mutex, NULL);
258*84e872a0SLloyd Pique 	pthread_cond_init(&display->reader_cond, NULL);
259*84e872a0SLloyd Pique 	display->reader_count = 0;
260*84e872a0SLloyd Pique+	wl_list_init(&display->observers);
261*84e872a0SLloyd Pique
262*84e872a0SLloyd Pique 	if (wl_map_insert_at(&display->objects, 0, 0, NULL) == -1)
263*84e872a0SLloyd Pique 		goto err_connection;
264*84e872a0SLloyd Pique@@ -1388,6 +1444,7 @@ wl_display_disconnect(struct wl_display *display)
265*84e872a0SLloyd Pique 	wl_map_release(&display->objects);
266*84e872a0SLloyd Pique 	wl_event_queue_release(&display->default_queue);
267*84e872a0SLloyd Pique 	wl_event_queue_release(&display->display_queue);
268*84e872a0SLloyd Pique+	wl_list_remove(&display->observers);
269*84e872a0SLloyd Pique 	pthread_mutex_destroy(&display->mutex);
270*84e872a0SLloyd Pique 	pthread_cond_destroy(&display->reader_cond);
271*84e872a0SLloyd Pique 	close(display->fd);
272*84e872a0SLloyd Pique@@ -1663,25 +1720,29 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
273*84e872a0SLloyd Pique 	proxy = closure->proxy;
274*84e872a0SLloyd Pique 	proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
275*84e872a0SLloyd Pique 	if (proxy_destroyed) {
276*84e872a0SLloyd Pique-		closure_log(closure, proxy, false, true);
277*84e872a0SLloyd Pique-		destroy_queued_closure(closure);
278*84e872a0SLloyd Pique-		return;
279*84e872a0SLloyd Pique-	}
280*84e872a0SLloyd Pique-
281*84e872a0SLloyd Pique-	pthread_mutex_unlock(&display->mutex);
282*84e872a0SLloyd Pique+		closure_log(closure, proxy, false,
283*84e872a0SLloyd Pique+			    WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH);
284*84e872a0SLloyd Pique+	} else if (proxy->dispatcher) {
285*84e872a0SLloyd Pique+		closure_log(closure, proxy, false,
286*84e872a0SLloyd Pique+			    WL_CLIENT_MESSAGE_NOT_DISCARDED);
287*84e872a0SLloyd Pique
288*84e872a0SLloyd Pique-	if (proxy->dispatcher) {
289*84e872a0SLloyd Pique-		closure_log(closure, proxy, false, false);
290*84e872a0SLloyd Pique+		pthread_mutex_unlock(&display->mutex);
291*84e872a0SLloyd Pique 		wl_closure_dispatch(closure, proxy->dispatcher,
292*84e872a0SLloyd Pique 				    &proxy->object, opcode);
293*84e872a0SLloyd Pique+		pthread_mutex_lock(&display->mutex);
294*84e872a0SLloyd Pique 	} else if (proxy->object.implementation) {
295*84e872a0SLloyd Pique-		closure_log(closure, proxy, false, false);
296*84e872a0SLloyd Pique+		closure_log(closure, proxy, false,
297*84e872a0SLloyd Pique+			    WL_CLIENT_MESSAGE_NOT_DISCARDED);
298*84e872a0SLloyd Pique+
299*84e872a0SLloyd Pique+		pthread_mutex_unlock(&display->mutex);
300*84e872a0SLloyd Pique 		wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
301*84e872a0SLloyd Pique 				  &proxy->object, opcode, proxy->user_data);
302*84e872a0SLloyd Pique+		pthread_mutex_lock(&display->mutex);
303*84e872a0SLloyd Pique+	} else {
304*84e872a0SLloyd Pique+		closure_log(closure, proxy, false,
305*84e872a0SLloyd Pique+			    WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH);
306*84e872a0SLloyd Pique 	}
307*84e872a0SLloyd Pique
308*84e872a0SLloyd Pique-	pthread_mutex_lock(&display->mutex);
309*84e872a0SLloyd Pique-
310*84e872a0SLloyd Pique 	destroy_queued_closure(closure);
311*84e872a0SLloyd Pique }
312*84e872a0SLloyd Pique
313*84e872a0SLloyd Pique@@ -2538,3 +2599,64 @@ wl_log_set_handler_client(wl_log_func_t handler)
314*84e872a0SLloyd Pique {
315*84e872a0SLloyd Pique 	wl_log_handler = handler;
316*84e872a0SLloyd Pique }
317*84e872a0SLloyd Pique+
318*84e872a0SLloyd Pique+/** Creates an client message observer.
319*84e872a0SLloyd Pique+ *
320*84e872a0SLloyd Pique+ * Note that the observer can potentially start receiving traffic immediately
321*84e872a0SLloyd Pique+ * after being created, and even before this call returns.
322*84e872a0SLloyd Pique+ *
323*84e872a0SLloyd Pique+ * \param display    client display to register with
324*84e872a0SLloyd Pique+ * \param func       function to call when client messages are observed
325*84e872a0SLloyd Pique+ * \param user_data  \c user_data pointer to pass to the observer
326*84e872a0SLloyd Pique+ *
327*84e872a0SLloyd Pique+ * \return The created observer, or NULL.
328*84e872a0SLloyd Pique+ *
329*84e872a0SLloyd Pique+ * \sa wl_client_observer_destroy
330*84e872a0SLloyd Pique+ *
331*84e872a0SLloyd Pique+ * \memberof wl_display
332*84e872a0SLloyd Pique+ */
333*84e872a0SLloyd Pique+
334*84e872a0SLloyd Pique+WL_EXPORT struct wl_client_observer *
335*84e872a0SLloyd Pique+wl_display_create_client_observer(struct wl_display *display,
336*84e872a0SLloyd Pique+				  wl_client_message_observer_func_t func,
337*84e872a0SLloyd Pique+				  void *user_data)
338*84e872a0SLloyd Pique+{
339*84e872a0SLloyd Pique+	struct wl_client_observer *observer;
340*84e872a0SLloyd Pique+
341*84e872a0SLloyd Pique+	observer = malloc(sizeof *observer);
342*84e872a0SLloyd Pique+	if (!observer)
343*84e872a0SLloyd Pique+		return NULL;
344*84e872a0SLloyd Pique+
345*84e872a0SLloyd Pique+	observer->display = display;
346*84e872a0SLloyd Pique+	observer->func = func;
347*84e872a0SLloyd Pique+	observer->user_data = user_data;
348*84e872a0SLloyd Pique+
349*84e872a0SLloyd Pique+	pthread_mutex_lock(&display->mutex);
350*84e872a0SLloyd Pique+
351*84e872a0SLloyd Pique+	wl_list_insert(&display->observers, &observer->link);
352*84e872a0SLloyd Pique+
353*84e872a0SLloyd Pique+	pthread_mutex_unlock(&display->mutex);
354*84e872a0SLloyd Pique+
355*84e872a0SLloyd Pique+	return observer;
356*84e872a0SLloyd Pique+}
357*84e872a0SLloyd Pique+
358*84e872a0SLloyd Pique+/** Destroys a client message obsever.
359*84e872a0SLloyd Pique+ *
360*84e872a0SLloyd Pique+ * This function destroys a client message observer, and removes it from the
361*84e872a0SLloyd Pique+ * display it was added to with \c wl_display_create_client_observer.
362*84e872a0SLloyd Pique+ *
363*84e872a0SLloyd Pique+ * \param observer observer to destroy.
364*84e872a0SLloyd Pique+ *
365*84e872a0SLloyd Pique+ * \memberof wl_client_observer
366*84e872a0SLloyd Pique+ */
367*84e872a0SLloyd Pique+WL_EXPORT void
368*84e872a0SLloyd Pique+wl_client_observer_destroy(struct wl_client_observer *observer)
369*84e872a0SLloyd Pique+{
370*84e872a0SLloyd Pique+	pthread_mutex_lock(&observer->display->mutex);
371*84e872a0SLloyd Pique+
372*84e872a0SLloyd Pique+	wl_list_remove(&observer->link);
373*84e872a0SLloyd Pique+
374*84e872a0SLloyd Pique+	pthread_mutex_unlock(&observer->display->mutex);
375*84e872a0SLloyd Pique+
376*84e872a0SLloyd Pique+	free(observer);
377*84e872a0SLloyd Pique+}
378*84e872a0SLloyd Piquediff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c
379*84e872a0SLloyd Piqueindex a0ebd22..3b9dc3e 100644
380*84e872a0SLloyd Pique--- a/tests/protocol-logger-test.c
381*84e872a0SLloyd Pique+++ b/tests/protocol-logger-test.c
382*84e872a0SLloyd Pique@@ -29,12 +29,15 @@
383*84e872a0SLloyd Pique #include <string.h>
384*84e872a0SLloyd Pique #include <stdio.h>
385*84e872a0SLloyd Pique #include <sys/un.h>
386*84e872a0SLloyd Pique+#include <time.h>
387*84e872a0SLloyd Pique #include <unistd.h>
388*84e872a0SLloyd Pique
389*84e872a0SLloyd Pique #include "wayland-client.h"
390*84e872a0SLloyd Pique #include "wayland-server.h"
391*84e872a0SLloyd Pique #include "test-runner.h"
392*84e872a0SLloyd Pique
393*84e872a0SLloyd Pique+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
394*84e872a0SLloyd Pique+
395*84e872a0SLloyd Pique /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
396*84e872a0SLloyd Pique static const char *
397*84e872a0SLloyd Pique require_xdg_runtime_dir(void)
398*84e872a0SLloyd Pique@@ -45,57 +48,146 @@ require_xdg_runtime_dir(void)
399*84e872a0SLloyd Pique 	return val;
400*84e872a0SLloyd Pique }
401*84e872a0SLloyd Pique
402*84e872a0SLloyd Pique+struct expected_compositor_message {
403*84e872a0SLloyd Pique+	enum wl_protocol_logger_type type;
404*84e872a0SLloyd Pique+	const char *class;
405*84e872a0SLloyd Pique+	int opcode;
406*84e872a0SLloyd Pique+	const char *message_name;
407*84e872a0SLloyd Pique+	int args_count;
408*84e872a0SLloyd Pique+};
409*84e872a0SLloyd Pique+
410*84e872a0SLloyd Pique struct compositor {
411*84e872a0SLloyd Pique 	struct wl_display *display;
412*84e872a0SLloyd Pique 	struct wl_event_loop *loop;
413*84e872a0SLloyd Pique-	int message;
414*84e872a0SLloyd Pique+	struct wl_protocol_logger *logger;
415*84e872a0SLloyd Pique+
416*84e872a0SLloyd Pique+	struct expected_compositor_message *expected_msg;
417*84e872a0SLloyd Pique+	int expected_msg_count;
418*84e872a0SLloyd Pique+	int actual_msg_count;
419*84e872a0SLloyd Pique 	struct wl_client *client;
420*84e872a0SLloyd Pique };
421*84e872a0SLloyd Pique
422*84e872a0SLloyd Pique-struct message {
423*84e872a0SLloyd Pique-	enum wl_protocol_logger_type type;
424*84e872a0SLloyd Pique+struct expected_client_message {
425*84e872a0SLloyd Pique+	enum wl_client_message_type type;
426*84e872a0SLloyd Pique+	enum wl_client_message_discarded_reason discarded_reason;
427*84e872a0SLloyd Pique 	const char *class;
428*84e872a0SLloyd Pique 	int opcode;
429*84e872a0SLloyd Pique 	const char *message_name;
430*84e872a0SLloyd Pique 	int args_count;
431*84e872a0SLloyd Pique-} messages[] = {
432*84e872a0SLloyd Pique-	{
433*84e872a0SLloyd Pique-		.type = WL_PROTOCOL_LOGGER_REQUEST,
434*84e872a0SLloyd Pique-		.class = "wl_display",
435*84e872a0SLloyd Pique-		.opcode = 0,
436*84e872a0SLloyd Pique-		.message_name = "sync",
437*84e872a0SLloyd Pique-		.args_count = 1,
438*84e872a0SLloyd Pique-	},
439*84e872a0SLloyd Pique-	{
440*84e872a0SLloyd Pique-		.type = WL_PROTOCOL_LOGGER_EVENT,
441*84e872a0SLloyd Pique-		.class = "wl_callback",
442*84e872a0SLloyd Pique-		.opcode = 0,
443*84e872a0SLloyd Pique-		.message_name = "done",
444*84e872a0SLloyd Pique-		.args_count = 1,
445*84e872a0SLloyd Pique-	},
446*84e872a0SLloyd Pique-	{
447*84e872a0SLloyd Pique-		.type = WL_PROTOCOL_LOGGER_EVENT,
448*84e872a0SLloyd Pique-		.class = "wl_display",
449*84e872a0SLloyd Pique-		.opcode = 1,
450*84e872a0SLloyd Pique-		.message_name = "delete_id",
451*84e872a0SLloyd Pique-		.args_count = 1,
452*84e872a0SLloyd Pique-	},
453*84e872a0SLloyd Pique };
454*84e872a0SLloyd Pique
455*84e872a0SLloyd Pique+struct client {
456*84e872a0SLloyd Pique+	struct wl_display *display;
457*84e872a0SLloyd Pique+	struct wl_callback *cb;
458*84e872a0SLloyd Pique+	struct wl_client_observer *sequence_observer;
459*84e872a0SLloyd Pique+
460*84e872a0SLloyd Pique+	struct expected_client_message *expected_msg;
461*84e872a0SLloyd Pique+	int expected_msg_count;
462*84e872a0SLloyd Pique+	int actual_msg_count;
463*84e872a0SLloyd Pique+};
464*84e872a0SLloyd Pique+
465*84e872a0SLloyd Pique+#define ASSERT_LT(arg1, arg2, ...)                                            \
466*84e872a0SLloyd Pique+	if (arg1 >= arg2)                                                     \
467*84e872a0SLloyd Pique+		fprintf(stderr, __VA_ARGS__);                                 \
468*84e872a0SLloyd Pique+	assert(arg1 < arg2)
469*84e872a0SLloyd Pique+
470*84e872a0SLloyd Pique+#define ASSERT_EQ(arg1, arg2, ...)                                            \
471*84e872a0SLloyd Pique+	if (arg1 != arg2)                                                     \
472*84e872a0SLloyd Pique+		fprintf(stderr, __VA_ARGS__);                                 \
473*84e872a0SLloyd Pique+	assert(arg1 == arg2)
474*84e872a0SLloyd Pique+
475*84e872a0SLloyd Pique+#define ASSERT_STR_EQ(arg1, arg2, ...)                                        \
476*84e872a0SLloyd Pique+	if (strcmp(arg1, arg2) != 0)                                          \
477*84e872a0SLloyd Pique+		fprintf(stderr, __VA_ARGS__);                                 \
478*84e872a0SLloyd Pique+	assert(strcmp(arg1, arg2) == 0)
479*84e872a0SLloyd Pique+
480*84e872a0SLloyd Pique static void
481*84e872a0SLloyd Pique-logger_func(void *user_data, enum wl_protocol_logger_type type,
482*84e872a0SLloyd Pique-	    const struct wl_protocol_logger_message *message)
483*84e872a0SLloyd Pique+compositor_sequence_observer_func(
484*84e872a0SLloyd Pique+	void *user_data, enum wl_protocol_logger_type actual_type,
485*84e872a0SLloyd Pique+	const struct wl_protocol_logger_message *actual_msg)
486*84e872a0SLloyd Pique {
487*84e872a0SLloyd Pique 	struct compositor *c = user_data;
488*84e872a0SLloyd Pique-	struct message *msg = &messages[c->message++];
489*84e872a0SLloyd Pique+	struct expected_compositor_message *expected_msg;
490*84e872a0SLloyd Pique+	int actual_msg_count = c->actual_msg_count++;
491*84e872a0SLloyd Pique+	char details_msg[256];
492*84e872a0SLloyd Pique+
493*84e872a0SLloyd Pique+	c->client = wl_resource_get_client(actual_msg->resource);
494*84e872a0SLloyd Pique+
495*84e872a0SLloyd Pique+	if (!c->expected_msg)
496*84e872a0SLloyd Pique+		return;
497*84e872a0SLloyd Pique+
498*84e872a0SLloyd Pique+	ASSERT_LT(actual_msg_count, c->expected_msg_count,
499*84e872a0SLloyd Pique+		  "actual count %d exceeds expected count %d\n",
500*84e872a0SLloyd Pique+		  actual_msg_count, c->expected_msg_count);
501*84e872a0SLloyd Pique+
502*84e872a0SLloyd Pique+	expected_msg = &c->expected_msg[actual_msg_count];
503*84e872a0SLloyd Pique+
504*84e872a0SLloyd Pique+	snprintf(details_msg, sizeof details_msg,
505*84e872a0SLloyd Pique+		 "compositor msg %d of %d actual [%d, '%s', %d, '%s', %d] vs "
506*84e872a0SLloyd Pique+		 "expected [%d, '%s', %d, '%s', %d]\n",
507*84e872a0SLloyd Pique+		 c->actual_msg_count, c->expected_msg_count, actual_type,
508*84e872a0SLloyd Pique+		 wl_resource_get_class(actual_msg->resource),
509*84e872a0SLloyd Pique+		 actual_msg->message_opcode, actual_msg->message->name,
510*84e872a0SLloyd Pique+		 actual_msg->arguments_count, expected_msg->type,
511*84e872a0SLloyd Pique+		 expected_msg->class, expected_msg->opcode,
512*84e872a0SLloyd Pique+		 expected_msg->message_name, expected_msg->args_count);
513*84e872a0SLloyd Pique
514*84e872a0SLloyd Pique-	assert(msg->type == type);
515*84e872a0SLloyd Pique-	assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0);
516*84e872a0SLloyd Pique-	assert(msg->opcode == message->message_opcode);
517*84e872a0SLloyd Pique-	assert(strcmp(msg->message_name, message->message->name) == 0);
518*84e872a0SLloyd Pique-	assert(msg->args_count == message->arguments_count);
519*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
520*84e872a0SLloyd Pique+		  details_msg);
521*84e872a0SLloyd Pique+	ASSERT_STR_EQ(expected_msg->class,
522*84e872a0SLloyd Pique+		      wl_resource_get_class(actual_msg->resource),
523*84e872a0SLloyd Pique+		      "class mismatch: %s", details_msg);
524*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
525*84e872a0SLloyd Pique+		  "opcode mismatch: %s", details_msg);
526*84e872a0SLloyd Pique+	ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
527*84e872a0SLloyd Pique+		      "message name mismatch: %s", details_msg);
528*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
529*84e872a0SLloyd Pique+		  "arg count mismatch: %s", details_msg);
530*84e872a0SLloyd Pique+}
531*84e872a0SLloyd Pique+
532*84e872a0SLloyd Pique+static void
533*84e872a0SLloyd Pique+client_sequence_observer_func(
534*84e872a0SLloyd Pique+	void *user_data, enum wl_client_message_type actual_type,
535*84e872a0SLloyd Pique+	const struct wl_client_observed_message *actual_msg)
536*84e872a0SLloyd Pique+{
537*84e872a0SLloyd Pique+	struct client *c = user_data;
538*84e872a0SLloyd Pique+	struct expected_client_message *expected_msg;
539*84e872a0SLloyd Pique+	int actual_msg_count = c->actual_msg_count++;
540*84e872a0SLloyd Pique+	char details_msg[256];
541*84e872a0SLloyd Pique+
542*84e872a0SLloyd Pique+	if (!c->expected_msg)
543*84e872a0SLloyd Pique+		return;
544*84e872a0SLloyd Pique+
545*84e872a0SLloyd Pique+	ASSERT_LT(actual_msg_count, c->expected_msg_count,
546*84e872a0SLloyd Pique+		  "actual count %d exceeds expected count %d\n",
547*84e872a0SLloyd Pique+		  actual_msg_count, c->expected_msg_count);
548*84e872a0SLloyd Pique+	expected_msg = &c->expected_msg[actual_msg_count];
549*84e872a0SLloyd Pique
550*84e872a0SLloyd Pique-	c->client = wl_resource_get_client(message->resource);
551*84e872a0SLloyd Pique+	snprintf(details_msg, sizeof details_msg,
552*84e872a0SLloyd Pique+		 "client msg %d of %d actual [%d, %d, '%s', %d, '%s', %d] vs "
553*84e872a0SLloyd Pique+		 "expected [%d, %d, '%s', %d, '%s', %d]\n",
554*84e872a0SLloyd Pique+		 c->actual_msg_count, c->expected_msg_count, actual_type,
555*84e872a0SLloyd Pique+		 actual_msg->discarded_reason,
556*84e872a0SLloyd Pique+		 wl_proxy_get_class(actual_msg->proxy),
557*84e872a0SLloyd Pique+		 actual_msg->message_opcode, actual_msg->message->name,
558*84e872a0SLloyd Pique+		 actual_msg->arguments_count, expected_msg->type,
559*84e872a0SLloyd Pique+		 expected_msg->discarded_reason, expected_msg->class,
560*84e872a0SLloyd Pique+		 expected_msg->opcode, expected_msg->message_name,
561*84e872a0SLloyd Pique+		 expected_msg->args_count);
562*84e872a0SLloyd Pique+
563*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s",
564*84e872a0SLloyd Pique+		  details_msg);
565*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->discarded_reason, actual_msg->discarded_reason,
566*84e872a0SLloyd Pique+		  "discarded reason mismatch: %s", details_msg);
567*84e872a0SLloyd Pique+	ASSERT_STR_EQ(expected_msg->class,
568*84e872a0SLloyd Pique+		      wl_proxy_get_class(actual_msg->proxy),
569*84e872a0SLloyd Pique+		      "class mismatch: %s", details_msg);
570*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode,
571*84e872a0SLloyd Pique+		  "opcode mismatch: %s", details_msg);
572*84e872a0SLloyd Pique+	ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name,
573*84e872a0SLloyd Pique+		      "message name mismatch: %s", details_msg);
574*84e872a0SLloyd Pique+	ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count,
575*84e872a0SLloyd Pique+		  "arg count mismatch: %s", details_msg);
576*84e872a0SLloyd Pique }
577*84e872a0SLloyd Pique
578*84e872a0SLloyd Pique static void
579*84e872a0SLloyd Pique@@ -108,41 +200,236 @@ static const struct wl_callback_listener callback_listener = {
580*84e872a0SLloyd Pique 	callback_done,
581*84e872a0SLloyd Pique };
582*84e872a0SLloyd Pique
583*84e872a0SLloyd Pique+static void
584*84e872a0SLloyd Pique+logger_setup(struct compositor *compositor, struct client *client)
585*84e872a0SLloyd Pique+{
586*84e872a0SLloyd Pique+	const char *socket;
587*84e872a0SLloyd Pique+
588*84e872a0SLloyd Pique+	require_xdg_runtime_dir();
589*84e872a0SLloyd Pique+
590*84e872a0SLloyd Pique+	compositor->display = wl_display_create();
591*84e872a0SLloyd Pique+	compositor->loop = wl_display_get_event_loop(compositor->display);
592*84e872a0SLloyd Pique+	socket = wl_display_add_socket_auto(compositor->display);
593*84e872a0SLloyd Pique+
594*84e872a0SLloyd Pique+	compositor->logger = wl_display_add_protocol_logger(
595*84e872a0SLloyd Pique+		compositor->display, compositor_sequence_observer_func,
596*84e872a0SLloyd Pique+		compositor);
597*84e872a0SLloyd Pique+
598*84e872a0SLloyd Pique+	client->display = wl_display_connect(socket);
599*84e872a0SLloyd Pique+	client->sequence_observer = wl_display_create_client_observer(
600*84e872a0SLloyd Pique+		client->display, client_sequence_observer_func, client);
601*84e872a0SLloyd Pique+}
602*84e872a0SLloyd Pique+
603*84e872a0SLloyd Pique+static void
604*84e872a0SLloyd Pique+logger_teardown(struct compositor *compositor, struct client *client)
605*84e872a0SLloyd Pique+{
606*84e872a0SLloyd Pique+	wl_client_observer_destroy(client->sequence_observer);
607*84e872a0SLloyd Pique+	wl_display_disconnect(client->display);
608*84e872a0SLloyd Pique+
609*84e872a0SLloyd Pique+	wl_client_destroy(compositor->client);
610*84e872a0SLloyd Pique+	wl_protocol_logger_destroy(compositor->logger);
611*84e872a0SLloyd Pique+	wl_display_destroy(compositor->display);
612*84e872a0SLloyd Pique+}
613*84e872a0SLloyd Pique+
614*84e872a0SLloyd Pique TEST(logger)
615*84e872a0SLloyd Pique {
616*84e872a0SLloyd Pique 	test_set_timeout(1);
617*84e872a0SLloyd Pique
618*84e872a0SLloyd Pique-	const char *socket;
619*84e872a0SLloyd Pique+	struct expected_compositor_message compositor_messages[] = {
620*84e872a0SLloyd Pique+		{
621*84e872a0SLloyd Pique+			.type = WL_PROTOCOL_LOGGER_REQUEST,
622*84e872a0SLloyd Pique+			.class = "wl_display",
623*84e872a0SLloyd Pique+			.opcode = 0,
624*84e872a0SLloyd Pique+			.message_name = "sync",
625*84e872a0SLloyd Pique+			.args_count = 1,
626*84e872a0SLloyd Pique+		},
627*84e872a0SLloyd Pique+		{
628*84e872a0SLloyd Pique+			.type = WL_PROTOCOL_LOGGER_EVENT,
629*84e872a0SLloyd Pique+			.class = "wl_callback",
630*84e872a0SLloyd Pique+			.opcode = 0,
631*84e872a0SLloyd Pique+			.message_name = "done",
632*84e872a0SLloyd Pique+			.args_count = 1,
633*84e872a0SLloyd Pique+		},
634*84e872a0SLloyd Pique+		{
635*84e872a0SLloyd Pique+			.type = WL_PROTOCOL_LOGGER_EVENT,
636*84e872a0SLloyd Pique+			.class = "wl_display",
637*84e872a0SLloyd Pique+			.opcode = 1,
638*84e872a0SLloyd Pique+			.message_name = "delete_id",
639*84e872a0SLloyd Pique+			.args_count = 1,
640*84e872a0SLloyd Pique+		},
641*84e872a0SLloyd Pique+	};
642*84e872a0SLloyd Pique+	struct expected_client_message client_messages[] = {
643*84e872a0SLloyd Pique+		{
644*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
645*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
646*84e872a0SLloyd Pique+			.class = "wl_display",
647*84e872a0SLloyd Pique+			.opcode = 0,
648*84e872a0SLloyd Pique+			.message_name = "sync",
649*84e872a0SLloyd Pique+			.args_count = 1,
650*84e872a0SLloyd Pique+		},
651*84e872a0SLloyd Pique+		{
652*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
653*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
654*84e872a0SLloyd Pique+			.class = "wl_display",
655*84e872a0SLloyd Pique+			.opcode = 1,
656*84e872a0SLloyd Pique+			.message_name = "delete_id",
657*84e872a0SLloyd Pique+			.args_count = 1,
658*84e872a0SLloyd Pique+		},
659*84e872a0SLloyd Pique+		{
660*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
661*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
662*84e872a0SLloyd Pique+			.class = "wl_callback",
663*84e872a0SLloyd Pique+			.opcode = 0,
664*84e872a0SLloyd Pique+			.message_name = "done",
665*84e872a0SLloyd Pique+			.args_count = 1,
666*84e872a0SLloyd Pique+		},
667*84e872a0SLloyd Pique+	};
668*84e872a0SLloyd Pique 	struct compositor compositor = { 0 };
669*84e872a0SLloyd Pique-	struct {
670*84e872a0SLloyd Pique-		struct wl_display *display;
671*84e872a0SLloyd Pique-		struct wl_callback *cb;
672*84e872a0SLloyd Pique-	} client;
673*84e872a0SLloyd Pique-	struct wl_protocol_logger *logger;
674*84e872a0SLloyd Pique+	struct client client = { 0 };
675*84e872a0SLloyd Pique
676*84e872a0SLloyd Pique-	require_xdg_runtime_dir();
677*84e872a0SLloyd Pique+	logger_setup(&compositor, &client);
678*84e872a0SLloyd Pique
679*84e872a0SLloyd Pique-	compositor.display = wl_display_create();
680*84e872a0SLloyd Pique-	compositor.loop = wl_display_get_event_loop(compositor.display);
681*84e872a0SLloyd Pique-	socket = wl_display_add_socket_auto(compositor.display);
682*84e872a0SLloyd Pique+	compositor.expected_msg = &compositor_messages[0];
683*84e872a0SLloyd Pique+	compositor.expected_msg_count = ARRAY_LENGTH(compositor_messages);
684*84e872a0SLloyd Pique
685*84e872a0SLloyd Pique-	logger = wl_display_add_protocol_logger(compositor.display,
686*84e872a0SLloyd Pique-						logger_func, &compositor);
687*84e872a0SLloyd Pique+	client.expected_msg = &client_messages[0];
688*84e872a0SLloyd Pique+	client.expected_msg_count = ARRAY_LENGTH(client_messages);
689*84e872a0SLloyd Pique
690*84e872a0SLloyd Pique-	client.display = wl_display_connect(socket);
691*84e872a0SLloyd Pique 	client.cb = wl_display_sync(client.display);
692*84e872a0SLloyd Pique 	wl_callback_add_listener(client.cb, &callback_listener, NULL);
693*84e872a0SLloyd Pique 	wl_display_flush(client.display);
694*84e872a0SLloyd Pique
695*84e872a0SLloyd Pique-	while (compositor.message < 3) {
696*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
697*84e872a0SLloyd Pique 		wl_event_loop_dispatch(compositor.loop, -1);
698*84e872a0SLloyd Pique 		wl_display_flush_clients(compositor.display);
699*84e872a0SLloyd Pique 	}
700*84e872a0SLloyd Pique
701*84e872a0SLloyd Pique-	wl_display_dispatch(client.display);
702*84e872a0SLloyd Pique-	wl_display_disconnect(client.display);
703*84e872a0SLloyd Pique+	while (client.actual_msg_count < client.expected_msg_count) {
704*84e872a0SLloyd Pique+		wl_display_dispatch(client.display);
705*84e872a0SLloyd Pique+	}
706*84e872a0SLloyd Pique+
707*84e872a0SLloyd Pique+	logger_teardown(&compositor, &client);
708*84e872a0SLloyd Pique+}
709*84e872a0SLloyd Pique+
710*84e872a0SLloyd Pique+TEST(client_discards_if_dead_on_dispatch)
711*84e872a0SLloyd Pique+{
712*84e872a0SLloyd Pique+	test_set_timeout(1);
713*84e872a0SLloyd Pique+
714*84e872a0SLloyd Pique+	struct expected_client_message client_messages[] = {
715*84e872a0SLloyd Pique+		{
716*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
717*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
718*84e872a0SLloyd Pique+			.class = "wl_display",
719*84e872a0SLloyd Pique+			.opcode = 0,
720*84e872a0SLloyd Pique+			.message_name = "sync",
721*84e872a0SLloyd Pique+			.args_count = 1,
722*84e872a0SLloyd Pique+		},
723*84e872a0SLloyd Pique+		{
724*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
725*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
726*84e872a0SLloyd Pique+			.class = "wl_display",
727*84e872a0SLloyd Pique+			.opcode = 1,
728*84e872a0SLloyd Pique+			.message_name = "delete_id",
729*84e872a0SLloyd Pique+			.args_count = 1,
730*84e872a0SLloyd Pique+		},
731*84e872a0SLloyd Pique+		{
732*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
733*84e872a0SLloyd Pique+			.discarded_reason =
734*84e872a0SLloyd Pique+				WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH,
735*84e872a0SLloyd Pique+			.class = "wl_callback",
736*84e872a0SLloyd Pique+			.opcode = 0,
737*84e872a0SLloyd Pique+			.message_name = "done",
738*84e872a0SLloyd Pique+			.args_count = 1,
739*84e872a0SLloyd Pique+		},
740*84e872a0SLloyd Pique+	};
741*84e872a0SLloyd Pique+	struct compositor compositor = { 0 };
742*84e872a0SLloyd Pique+	struct client client = { 0 };
743*84e872a0SLloyd Pique+
744*84e872a0SLloyd Pique+	logger_setup(&compositor, &client);
745*84e872a0SLloyd Pique+
746*84e872a0SLloyd Pique+	compositor.expected_msg_count = 3;
747*84e872a0SLloyd Pique+
748*84e872a0SLloyd Pique+	client.expected_msg = &client_messages[0];
749*84e872a0SLloyd Pique+	client.expected_msg_count = ARRAY_LENGTH(client_messages);
750*84e872a0SLloyd Pique+
751*84e872a0SLloyd Pique+	client.cb = wl_display_sync(client.display);
752*84e872a0SLloyd Pique+	wl_callback_add_listener(client.cb, &callback_listener, NULL);
753*84e872a0SLloyd Pique+	wl_display_flush(client.display);
754*84e872a0SLloyd Pique+
755*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
756*84e872a0SLloyd Pique+		wl_event_loop_dispatch(compositor.loop, -1);
757*84e872a0SLloyd Pique+		wl_display_flush_clients(compositor.display);
758*84e872a0SLloyd Pique+	}
759*84e872a0SLloyd Pique+
760*84e872a0SLloyd Pique+	wl_display_prepare_read(client.display);
761*84e872a0SLloyd Pique+	wl_display_read_events(client.display);
762*84e872a0SLloyd Pique+
763*84e872a0SLloyd Pique+	// To get a WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH, we
764*84e872a0SLloyd Pique+	// destroy the callback after reading client events, but before
765*84e872a0SLloyd Pique+	// dispatching them.
766*84e872a0SLloyd Pique+	wl_callback_destroy(client.cb);
767*84e872a0SLloyd Pique+
768*84e872a0SLloyd Pique+	while (client.actual_msg_count < client.expected_msg_count) {
769*84e872a0SLloyd Pique+		wl_display_dispatch(client.display);
770*84e872a0SLloyd Pique+	}
771*84e872a0SLloyd Pique+
772*84e872a0SLloyd Pique+	logger_teardown(&compositor, &client);
773*84e872a0SLloyd Pique+}
774*84e872a0SLloyd Pique+
775*84e872a0SLloyd Pique+TEST(client_discards_if_no_listener_on_dispatch)
776*84e872a0SLloyd Pique+{
777*84e872a0SLloyd Pique+	test_set_timeout(1);
778*84e872a0SLloyd Pique+
779*84e872a0SLloyd Pique+	struct expected_client_message client_messages[] = {
780*84e872a0SLloyd Pique+		{
781*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_REQUEST,
782*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
783*84e872a0SLloyd Pique+			.class = "wl_display",
784*84e872a0SLloyd Pique+			.opcode = 0,
785*84e872a0SLloyd Pique+			.message_name = "sync",
786*84e872a0SLloyd Pique+			.args_count = 1,
787*84e872a0SLloyd Pique+		},
788*84e872a0SLloyd Pique+		{
789*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
790*84e872a0SLloyd Pique+			.discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED,
791*84e872a0SLloyd Pique+			.class = "wl_display",
792*84e872a0SLloyd Pique+			.opcode = 1,
793*84e872a0SLloyd Pique+			.message_name = "delete_id",
794*84e872a0SLloyd Pique+			.args_count = 1,
795*84e872a0SLloyd Pique+		},
796*84e872a0SLloyd Pique+		{
797*84e872a0SLloyd Pique+			.type = WL_CLIENT_MESSAGE_EVENT,
798*84e872a0SLloyd Pique+			.discarded_reason =
799*84e872a0SLloyd Pique+				WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH,
800*84e872a0SLloyd Pique+			.class = "wl_callback",
801*84e872a0SLloyd Pique+			.opcode = 0,
802*84e872a0SLloyd Pique+			.message_name = "done",
803*84e872a0SLloyd Pique+			.args_count = 1,
804*84e872a0SLloyd Pique+		},
805*84e872a0SLloyd Pique+	};
806*84e872a0SLloyd Pique+	struct compositor compositor = { 0 };
807*84e872a0SLloyd Pique+	struct client client = { 0 };
808*84e872a0SLloyd Pique+
809*84e872a0SLloyd Pique+	logger_setup(&compositor, &client);
810*84e872a0SLloyd Pique+
811*84e872a0SLloyd Pique+	compositor.expected_msg_count = 3;
812*84e872a0SLloyd Pique+
813*84e872a0SLloyd Pique+	client.expected_msg = &client_messages[0];
814*84e872a0SLloyd Pique+	client.expected_msg_count = ARRAY_LENGTH(client_messages);
815*84e872a0SLloyd Pique+
816*84e872a0SLloyd Pique+	client.cb = wl_display_sync(client.display);
817*84e872a0SLloyd Pique+	wl_display_flush(client.display);
818*84e872a0SLloyd Pique+
819*84e872a0SLloyd Pique+	while (compositor.actual_msg_count < compositor.expected_msg_count) {
820*84e872a0SLloyd Pique+		wl_event_loop_dispatch(compositor.loop, -1);
821*84e872a0SLloyd Pique+		wl_display_flush_clients(compositor.display);
822*84e872a0SLloyd Pique+	}
823*84e872a0SLloyd Pique+
824*84e872a0SLloyd Pique+	while (client.actual_msg_count < client.expected_msg_count) {
825*84e872a0SLloyd Pique+		wl_display_dispatch(client.display);
826*84e872a0SLloyd Pique+	}
827*84e872a0SLloyd Pique+
828*84e872a0SLloyd Pique+	wl_callback_destroy(client.cb);
829*84e872a0SLloyd Pique
830*84e872a0SLloyd Pique-	wl_client_destroy(compositor.client);
831*84e872a0SLloyd Pique-	wl_protocol_logger_destroy(logger);
832*84e872a0SLloyd Pique-	wl_display_destroy(compositor.display);
833*84e872a0SLloyd Pique+	logger_teardown(&compositor, &client);
834*84e872a0SLloyd Pique }
835