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, ®istry_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