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