diff options
Diffstat (limited to 'tests/protocol-logger-test.c')
-rw-r--r-- | tests/protocol-logger-test.c | 772 |
1 files changed, 634 insertions, 138 deletions
diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c index b66e761..94e437d 100644 --- a/tests/protocol-logger-test.c +++ b/tests/protocol-logger-test.c @@ -34,125 +34,166 @@ #include "wayland-client.h" #include "wayland-server.h" -#include "wayland-util.h" #include "test-runner.h" +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0]) + /* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ static const char * require_xdg_runtime_dir(void) { char *val = getenv("XDG_RUNTIME_DIR"); - assert(val && "set $XDG_RUNTIME_DIR to run this test"); + assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test"); return val; } +struct expected_compositor_message { + enum wl_protocol_logger_type type; + const char *class; + int opcode; + const char *message_name; + int args_count; +}; + struct compositor { struct wl_display *display; struct wl_event_loop *loop; - int message; - struct wl_client *client; -}; + struct wl_protocol_logger *logger; -struct client { - struct wl_display *display; - struct wl_callback *cb; - int message; + struct expected_compositor_message *expected_msg; + int expected_msg_count; + int actual_msg_count; + struct wl_client *client; }; -struct message { - enum wl_protocol_logger_type type; +struct expected_client_message { + enum wl_client_message_type type; + enum wl_client_message_discarded_reason discarded_reason; const char *class; int opcode; const char *message_name; int args_count; -} messages[] = { - { - .type = WL_PROTOCOL_LOGGER_REQUEST, - .class = "wl_display", - .opcode = 0, - .message_name = "sync", - .args_count = 1, - }, - { - .type = WL_PROTOCOL_LOGGER_EVENT, - .class = "wl_callback", - .opcode = 0, - .message_name = "done", - .args_count = 1, - }, - { - .type = WL_PROTOCOL_LOGGER_EVENT, - .class = "wl_display", - .opcode = 1, - .message_name = "delete_id", - .args_count = 1, - }, }; -struct client_message { - enum wl_protocol_logger_client_type type; - const char *class; - int opcode; - const char *message_name; - int args_count; -} client_messages[] = { - { - .type = WL_PROTOCOL_LOGGER_CLIENT_REQUEST, - .class = "wl_display", - .opcode = 0, - .message_name = "sync", - .args_count = 1, - }, - { - .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT, - .class = "wl_display", - .opcode = 1, - .message_name = "delete_id", - .args_count = 1, - }, - { - .type = WL_PROTOCOL_LOGGER_CLIENT_EVENT, - .class = "wl_callback", - .opcode = 0, - .message_name = "done", - .args_count = 1, - }, +struct client { + struct wl_display *display; + struct wl_callback *cb; + struct wl_client_observer *sequence_observer; + struct wl_client_observer *stderr_logger; + + struct expected_client_message *expected_msg; + int expected_msg_count; + int actual_msg_count; }; +#define ASSERT_LT(arg1, arg2, ...) \ + if (arg1 >= arg2) \ + fprintf(stderr, __VA_ARGS__); \ + assert(arg1 < arg2) + +#define ASSERT_EQ(arg1, arg2, ...) \ + if (arg1 != arg2) \ + fprintf(stderr, __VA_ARGS__); \ + assert(arg1 == arg2) + +#define ASSERT_STR_EQ(arg1, arg2, ...) \ + if (strcmp(arg1, arg2) != 0) \ + fprintf(stderr, __VA_ARGS__); \ + assert(strcmp(arg1, arg2) == 0) + static void -logger_func(void *user_data, enum wl_protocol_logger_type type, - const struct wl_protocol_logger_message *message) +compositor_sequence_observer_func( + void *user_data, enum wl_protocol_logger_type actual_type, + const struct wl_protocol_logger_message *actual_msg) { struct compositor *c = user_data; - struct message *msg = &messages[c->message++]; - - assert(msg->type == type); - assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0); - assert(msg->opcode == message->message_opcode); - assert(strcmp(msg->message_name, message->message->name) == 0); - assert(msg->args_count == message->arguments_count); - - c->client = wl_resource_get_client(message->resource); + struct expected_compositor_message *expected_msg; + int actual_msg_count = c->actual_msg_count++; + char details_msg[256]; + + c->client = wl_resource_get_client(actual_msg->resource); + + if (!c->expected_msg) + return; + + ASSERT_LT(actual_msg_count, c->expected_msg_count, + "actual count %d exceeds expected count %d\n", + actual_msg_count, c->expected_msg_count); + + expected_msg = &c->expected_msg[actual_msg_count]; + + snprintf(details_msg, sizeof details_msg, + "compositor msg %d of %d actual [%d, '%s', %d, '%s', %d] vs " + "expected [%d, '%s', %d, '%s', %d]\n", + c->actual_msg_count, c->expected_msg_count, actual_type, + wl_resource_get_class(actual_msg->resource), + actual_msg->message_opcode, actual_msg->message->name, + actual_msg->arguments_count, expected_msg->type, + expected_msg->class, expected_msg->opcode, + expected_msg->message_name, expected_msg->args_count); + + ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s", + details_msg); + ASSERT_STR_EQ(expected_msg->class, + wl_resource_get_class(actual_msg->resource), + "class mismatch: %s", details_msg); + ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode, + "opcode mismatch: %s", details_msg); + ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name, + "message name mismatch: %s", details_msg); + ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count, + "arg count mismatch: %s", details_msg); } static void -client_logger_func(void *user_data, enum wl_protocol_logger_client_type type, - const struct wl_protocol_logger_client_message *message) +client_sequence_observer_func( + void *user_data, enum wl_client_message_type actual_type, + const struct wl_client_observed_message *actual_msg) { struct client *c = user_data; - struct client_message *msg = &client_messages[c->message++]; - - assert(msg->type == type); - assert(strcmp(msg->class, wl_proxy_get_class(message->proxy)) == 0); - assert(msg->opcode == message->message_opcode); - assert(strcmp(msg->message_name, message->message->name) == 0); - assert(msg->args_count == message->arguments_count); + struct expected_client_message *expected_msg; + int actual_msg_count = c->actual_msg_count++; + char details_msg[256]; + + if (!c->expected_msg) + return; + + ASSERT_LT(actual_msg_count, c->expected_msg_count, + "actual count %d exceeds expected count %d\n", + actual_msg_count, c->expected_msg_count); + expected_msg = &c->expected_msg[actual_msg_count]; + + snprintf(details_msg, sizeof details_msg, + "client msg %d of %d actual [%d, %d, '%s', %d, '%s', %d] vs " + "expected [%d, %d, '%s', %d, '%s', %d]\n", + c->actual_msg_count, c->expected_msg_count, actual_type, + actual_msg->discarded_reason, + wl_proxy_get_class(actual_msg->proxy), + actual_msg->message_opcode, actual_msg->message->name, + actual_msg->arguments_count, expected_msg->type, + expected_msg->discarded_reason, expected_msg->class, + expected_msg->opcode, expected_msg->message_name, + expected_msg->args_count); + + ASSERT_EQ(expected_msg->type, actual_type, "type mismatch: %s", + details_msg); + ASSERT_EQ(expected_msg->discarded_reason, actual_msg->discarded_reason, + "discarded reason mismatch: %s", details_msg); + ASSERT_STR_EQ(expected_msg->class, + wl_proxy_get_class(actual_msg->proxy), + "class mismatch: %s", details_msg); + ASSERT_EQ(expected_msg->opcode, actual_msg->message_opcode, + "opcode mismatch: %s", details_msg); + ASSERT_STR_EQ(expected_msg->message_name, actual_msg->message->name, + "message name mismatch: %s", details_msg); + ASSERT_EQ(expected_msg->args_count, actual_msg->arguments_count, + "arg count mismatch: %s", details_msg); } -// A slightly simplified version of get_next_argument() from src/connection.c -static const char* -get_next_argument_type(const char *signature, char* type) +// A slightly simplified version of get_next_argument() from src/connection.c +static const char * +get_next_argument_type(const char *signature, char *type) { for (; *signature; ++signature) { assert(strchr("iufsonah?", *signature) != NULL); @@ -169,7 +210,6 @@ get_next_argument_type(const char *signature, char* type) return signature + 1; case '?': break; - } } *type = 0; @@ -179,85 +219,101 @@ get_next_argument_type(const char *signature, char* type) // This duplicates what the internal wl_closure_print function does, and can be // used as a starting point for a client or server that wants to log messages. static void -client_log_to_stderr_demo(void *user_data, - enum wl_protocol_logger_client_type type, - const struct wl_protocol_logger_client_message *message) { +client_log_to_stderr_demo(void *user_data, enum wl_client_message_type type, + const struct wl_client_observed_message *message) +{ int i; char arg_type; const char *signature = message->message->signature; - const union wl_argument* args = message->arguments; - struct wl_proxy* arg_proxy; - const char* arg_class; + const union wl_argument *args = message->arguments; + struct wl_proxy *arg_proxy; + const char *arg_class; struct timespec tp; - unsigned int time; + unsigned long long time; + FILE *f; + char *buffer; + size_t buffer_length; + + f = open_memstream(&buffer, &buffer_length); + if (f == NULL) + return; clock_gettime(CLOCK_REALTIME, &tp); - time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + time = (tp.tv_sec * 1000000LL) + (tp.tv_nsec / 1000); // Note: server logger will be given message->resource, and should // use wl_resource_get_class and wl_resolurce_get_id. - fprintf(stderr, "[%10.3f] %s%s@%u.%s(", - time / 1000.0, - (type == WL_PROTOCOL_LOGGER_CLIENT_REQUEST) ? " -> " : "", - wl_proxy_get_class(message->proxy), wl_proxy_get_id(message->proxy), - message->message->name); + fprintf(f, "[%7llu.%03llu] %s%s%s%s%s@%u.%s(", time / 1000, time % 1000, + (message->discarded_reason_str ? "discarded[" : ""), + (message->discarded_reason_str ? message->discarded_reason_str + : ""), + (message->discarded_reason_str ? "] " : ""), + (type == WL_CLIENT_MESSAGE_REQUEST) ? " -> " : "", + wl_proxy_get_class(message->proxy), + wl_proxy_get_id(message->proxy), message->message->name); for (i = 0; i < message->arguments_count; i++) { signature = get_next_argument_type(signature, &arg_type); if (i > 0) - fprintf(stderr, ", "); + fprintf(f, ", "); switch (arg_type) { case 'u': - fprintf(stderr, "%u", args[i].u); + fprintf(f, "%u", args[i].u); break; case 'i': - fprintf(stderr, "%d", args[i].i); + fprintf(f, "%d", args[i].i); break; case 'f': - fprintf(stderr, "%f", wl_fixed_to_double(args[i].f)); + fprintf(f, "%f", wl_fixed_to_double(args[i].f)); break; case 's': if (args[i].s) - fprintf(stderr, "\"%s\"", args[i].s); + fprintf(f, "\"%s\"", args[i].s); else - fprintf(stderr, "nil"); + fprintf(f, "nil"); break; case 'o': if (args[i].o) { // Note: server logger should instead use // wl_resource_from_object, and then - // wl_resource_get_class and wl_resource_get_id. + // wl_resource_get_class and + // wl_resource_get_id. arg_proxy = wl_proxy_from_object(args[i].o); arg_class = wl_proxy_get_class(arg_proxy); - fprintf(stderr, "%s@%u", + fprintf(f, "%s@%u", arg_class ? arg_class : "[unknown]", wl_proxy_get_id(arg_proxy)); } else { - fprintf(stderr, "nil"); + fprintf(f, "nil"); } break; case 'n': - fprintf(stderr, "new id %s@", - (message->message->types[i]) ? - message->message->types[i]->name : - "[unknown]"); + fprintf(f, "new id %s@", + (message->message->types[i]) + ? message->message->types[i]->name + : "[unknown]"); if (args[i].n != 0) - fprintf(stderr, "%u", args[i].n); + fprintf(f, "%u", args[i].n); else - fprintf(stderr, "nil"); + fprintf(f, "nil"); break; case 'a': - fprintf(stderr, "array"); + fprintf(f, "array"); break; case 'h': - fprintf(stderr, "fd %d", args[i].h); + fprintf(f, "fd %d", args[i].h); break; } } - fprintf(stderr, ")\n"); + fprintf(f, ")\n"); + + if (fclose(f) == 0) { + fprintf(stderr, "%s", buffer); + free(buffer); + } } static void @@ -270,46 +326,486 @@ static const struct wl_callback_listener callback_listener = { callback_done, }; +static void +logger_setup(struct compositor *compositor, struct client *client) +{ + const char *socket; + + require_xdg_runtime_dir(); + + compositor->display = wl_display_create(); + compositor->loop = wl_display_get_event_loop(compositor->display); + socket = wl_display_add_socket_auto(compositor->display); + + compositor->logger = wl_display_add_protocol_logger( + compositor->display, compositor_sequence_observer_func, + compositor); + + client->display = wl_display_connect(socket); + client->sequence_observer = wl_display_create_client_observer( + client->display, client_sequence_observer_func, client); + client->stderr_logger = wl_display_create_client_observer( + client->display, client_log_to_stderr_demo, client); +} + +static void +logger_teardown(struct compositor *compositor, struct client *client) +{ + wl_client_observer_destroy(client->sequence_observer); + wl_client_observer_destroy(client->stderr_logger); + wl_display_disconnect(client->display); + + wl_client_destroy(compositor->client); + wl_protocol_logger_destroy(compositor->logger); + wl_display_destroy(compositor->display); +} + TEST(logger) { test_set_timeout(1); - const char *socket; + struct expected_compositor_message compositor_messages[] = { + { + .type = WL_PROTOCOL_LOGGER_REQUEST, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_PROTOCOL_LOGGER_EVENT, + .class = "wl_callback", + .opcode = 0, + .message_name = "done", + .args_count = 1, + }, + { + .type = WL_PROTOCOL_LOGGER_EVENT, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, + }; + struct expected_client_message client_messages[] = { + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_callback", + .opcode = 0, + .message_name = "done", + .args_count = 1, + }, + }; struct compositor compositor = { 0 }; struct client client = { 0 }; - struct wl_protocol_logger *logger; - struct wl_protocol_logger_client *logger_client; - struct wl_protocol_logger_client *logger_client_demo; - require_xdg_runtime_dir(); + logger_setup(&compositor, &client); + + compositor.expected_msg = &compositor_messages[0]; + compositor.expected_msg_count = ARRAY_LENGTH(compositor_messages); + + client.expected_msg = &client_messages[0]; + client.expected_msg_count = ARRAY_LENGTH(client_messages); + + client.cb = wl_display_sync(client.display); + wl_callback_add_listener(client.cb, &callback_listener, NULL); + wl_display_flush(client.display); + + while (compositor.actual_msg_count < compositor.expected_msg_count) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + while (client.actual_msg_count < client.expected_msg_count) { + wl_display_dispatch(client.display); + } + + logger_teardown(&compositor, &client); +} + +TEST(client_discards_if_dead_on_dispatch) +{ + test_set_timeout(1); + + struct expected_client_message client_messages[] = { + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = + WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH, + .class = "wl_callback", + .opcode = 0, + .message_name = "done", + .args_count = 1, + }, + }; + struct compositor compositor = { 0 }; + struct client client = { 0 }; + + logger_setup(&compositor, &client); - compositor.display = wl_display_create(); - compositor.loop = wl_display_get_event_loop(compositor.display); - socket = wl_display_add_socket_auto(compositor.display); + compositor.expected_msg_count = 3; - logger = wl_display_add_protocol_logger(compositor.display, - logger_func, &compositor); + client.expected_msg = &client_messages[0]; + client.expected_msg_count = ARRAY_LENGTH(client_messages); - client.display = wl_display_connect(socket); - logger_client = wl_display_add_protocol_logger_client( - client.display, client_logger_func, &client); - logger_client_demo = wl_display_add_protocol_logger_client( - client.display, client_log_to_stderr_demo, &client); client.cb = wl_display_sync(client.display); wl_callback_add_listener(client.cb, &callback_listener, NULL); wl_display_flush(client.display); - while (compositor.message < 3) { + while (compositor.actual_msg_count < compositor.expected_msg_count) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + wl_display_prepare_read(client.display); + wl_display_read_events(client.display); + + // To get a WL_CLIENT_MESSAGE_DISCARD_DEAD_PROXY_ON_DISPATCH, we + // destroy the callback after reading client events, but before + // dispatching them. + wl_callback_destroy(client.cb); + + while (client.actual_msg_count < client.expected_msg_count) { + wl_display_dispatch(client.display); + } + + logger_teardown(&compositor, &client); +} + +TEST(client_discards_if_no_listener_on_dispatch) +{ + test_set_timeout(1); + + struct expected_client_message client_messages[] = { + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = + WL_CLIENT_MESSAGE_DISCARD_NO_LISTENER_ON_DISPATCH, + .class = "wl_callback", + .opcode = 0, + .message_name = "done", + .args_count = 1, + }, + }; + struct compositor compositor = { 0 }; + struct client client = { 0 }; + + logger_setup(&compositor, &client); + + compositor.expected_msg_count = 3; + + client.expected_msg = &client_messages[0]; + client.expected_msg_count = ARRAY_LENGTH(client_messages); + + client.cb = wl_display_sync(client.display); + wl_display_flush(client.display); + + while (compositor.actual_msg_count < compositor.expected_msg_count) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + while (client.actual_msg_count < client.expected_msg_count) { + wl_display_dispatch(client.display); + } + + wl_callback_destroy(client.cb); + + logger_teardown(&compositor, &client); +} + +TEST(client_discards_if_invalid_id_on_demarshal) +{ + test_set_timeout(1); + + struct expected_client_message client_messages[] = { + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 0, + .message_name = "sync", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = + WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, + .class = "[unknown]", + .opcode = 0, + .message_name = "[event 0, 0 fds, 12 bytes]", + .args_count = 0, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 1, + .message_name = "delete_id", + .args_count = 1, + }, + }; + struct compositor compositor = { 0 }; + struct client client = { 0 }; + + logger_setup(&compositor, &client); + + compositor.expected_msg_count = 3; + + client.expected_msg = &client_messages[0]; + client.expected_msg_count = ARRAY_LENGTH(client_messages); + + client.cb = wl_display_sync(client.display); + wl_display_flush(client.display); + + while (compositor.actual_msg_count < compositor.expected_msg_count) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + // To get a WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, we + // destroy the callback before reading and dispatching client events. + wl_callback_destroy(client.cb); + + while (client.actual_msg_count < client.expected_msg_count) { + wl_display_dispatch(client.display); + } + + logger_teardown(&compositor, &client); +} + +static const struct wl_keyboard_interface keyboard_interface = { 0 }; + +static void +seat_get_pointer(struct wl_client *client, struct wl_resource *resource, + uint32_t id) +{ + assert(false && "Not expected to be called by client."); +} + +static void +seat_get_keyboard(struct wl_client *client, struct wl_resource *resource, + uint32_t id) +{ + struct wl_resource *keyboard_res; + + keyboard_res = + wl_resource_create(client, &wl_keyboard_interface, + wl_resource_get_version(resource), id); + wl_resource_set_implementation(keyboard_res, &keyboard_interface, NULL, + NULL); + + wl_keyboard_send_key(keyboard_res, 0, 0, 0, 0); +} + +static void +seat_get_touch(struct wl_client *client, struct wl_resource *resource, + uint32_t id) +{ + assert(false && "Not expected to be called by client."); +} + +static void +seat_release(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct wl_seat_interface seat_interface = { + &seat_get_pointer, + &seat_get_keyboard, + &seat_get_touch, + &seat_release, +}; + +static void +bind_seat(struct wl_client *client, void *data, uint32_t vers, uint32_t id) +{ + struct wl_resource *seat_res; + + seat_res = wl_resource_create(client, &wl_seat_interface, vers, id); + wl_resource_set_implementation(seat_res, &seat_interface, NULL, NULL); +} + +static void +registry_seat_listener_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *intf, + uint32_t ver) +{ + uint32_t *seat_id_ptr = data; + + if (strcmp(intf, wl_seat_interface.name) == 0) { + *seat_id_ptr = id; + } +} + +static const struct wl_registry_listener registry_seat_listener = { + registry_seat_listener_handle_global, NULL +}; + +TEST(client_discards_if_zombie_on_demarshal) +{ + test_set_timeout(1); + + struct expected_client_message client_messages[] = { + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_display", + .opcode = 1, + .message_name = "get_registry", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_registry", + .opcode = 0, + .message_name = "global", + .args_count = 3, + }, + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_registry", + .opcode = 0, + .message_name = "bind", + .args_count = 4, + }, + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_seat", + .opcode = 1, + .message_name = "get_keyboard", + .args_count = 1, + }, + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_keyboard", + .opcode = 0, + .message_name = "release", + .args_count = 0, + }, + { + .type = WL_CLIENT_MESSAGE_REQUEST, + .discarded_reason = WL_CLIENT_MESSAGE_NOT_DISCARDED, + .class = "wl_seat", + .opcode = 3, + .message_name = "release", + .args_count = 0, + }, + { + .type = WL_CLIENT_MESSAGE_EVENT, + .discarded_reason = + WL_CLIENT_MESSAGE_DISCARD_UNKNOWN_ID_ON_DEMARSHAL, + .class = "[zombie]", + .opcode = 3, + .message_name = "[event 3, 0 fds, 24 bytes]", + .args_count = 0, + }, + }; + + struct compositor compositor = { 0 }; + struct client client = { 0 }; + struct wl_global *g_keyboard; + struct wl_registry *registry; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + int32_t seat_id; + + logger_setup(&compositor, &client); + + client.expected_msg = &client_messages[0]; + client.expected_msg_count = ARRAY_LENGTH(client_messages); + + g_keyboard = wl_global_create(compositor.display, &wl_seat_interface, + 5, &compositor.display, bind_seat); + + registry = wl_display_get_registry(client.display); + wl_registry_add_listener(registry, ®istry_seat_listener, &seat_id); + wl_display_flush(client.display); + + compositor.actual_msg_count = 0; + compositor.expected_msg_count = 2; + + while (compositor.actual_msg_count < compositor.expected_msg_count) { wl_event_loop_dispatch(compositor.loop, -1); wl_display_flush_clients(compositor.display); } wl_display_dispatch(client.display); - wl_display_disconnect(client.display); - wl_protocol_logger_client_destroy(logger_client); - wl_protocol_logger_client_destroy(logger_client_demo); - wl_client_destroy(compositor.client); - wl_protocol_logger_destroy(logger); - wl_display_destroy(compositor.display); + seat = wl_registry_bind(registry, seat_id, &wl_seat_interface, 5); + keyboard = wl_seat_get_keyboard(seat); + wl_display_flush(client.display); + + compositor.actual_msg_count = 0; + compositor.expected_msg_count = 3; + + while (compositor.actual_msg_count < compositor.expected_msg_count) { + wl_event_loop_dispatch(compositor.loop, -1); + wl_display_flush_clients(compositor.display); + } + + wl_keyboard_release(keyboard); + wl_seat_release(seat); + + wl_display_dispatch(client.display); + + wl_registry_destroy(registry); + + wl_global_destroy(g_keyboard); + + logger_teardown(&compositor, &client); } |