1/* 2 * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial 14 * portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25 26#include <stdlib.h> 27#include <assert.h> 28#include <errno.h> 29#include <string.h> 30#include <stdio.h> 31#include <sys/un.h> 32#include <unistd.h> 33 34#include "wayland-client.h" 35#include "wayland-server.h" 36#include "test-runner.h" 37 38/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */ 39static const char * 40require_xdg_runtime_dir(void) 41{ 42 char *val = getenv("XDG_RUNTIME_DIR"); 43 assert(val && "set $XDG_RUNTIME_DIR to run this test"); 44 45 return val; 46} 47 48struct compositor { 49 struct wl_display *display; 50 struct wl_listener listener; 51 struct wl_client *client; 52}; 53 54static void 55client_created(struct wl_listener *listener, void *data) 56{ 57 struct compositor *c = wl_container_of(listener, c, listener); 58 c->client = data; 59} 60 61static void 62check_client_list(struct compositor *compositor) 63{ 64 struct wl_list *client_list; 65 struct wl_client *client, *client_it; 66 int num_clients = 0; 67 68 client_list = wl_display_get_client_list(compositor->display); 69 wl_client_for_each(client_it, client_list) { 70 num_clients++; 71 client = client_it; 72 } 73 assert(num_clients == 1); 74 /* 'client_it' is not valid here, so we took a copy of the client in the loop. 75 * We could also do this assert in the loop directly, but in case it fails it is 76 * easier to understand the problem when we know that the previous assert passed, 77 * so that there is only one client but the wrong one. */ 78 assert(compositor->client == client); 79} 80 81static const char * 82setup_compositor(struct compositor *compositor) 83{ 84 const char *socket; 85 86 require_xdg_runtime_dir(); 87 88 compositor->display = wl_display_create(); 89 socket = wl_display_add_socket_auto(compositor->display); 90 91 compositor->listener.notify = client_created; 92 wl_display_add_client_created_listener(compositor->display, &compositor->listener); 93 94 return socket; 95} 96 97static void 98cleanup_compositor(struct compositor *compositor) 99{ 100 wl_client_destroy(compositor->client); 101 wl_display_destroy(compositor->display); 102} 103 104TEST(new_client_connect) 105{ 106 const char *socket; 107 struct compositor compositor = { 0 }; 108 struct { 109 struct wl_display *display; 110 } client; 111 112 socket = setup_compositor(&compositor); 113 114 client.display = wl_display_connect(socket); 115 116 wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); 117 118 assert(compositor.client != NULL); 119 120 check_client_list(&compositor); 121 122 123 124 wl_display_disconnect(client.display); 125 cleanup_compositor(&compositor); 126} 127 128struct resource_listener { 129 struct wl_listener listener; 130 int count; 131}; 132 133static void 134resource_created(struct wl_listener *listener, void *data) 135{ 136 struct resource_listener *l; 137 l = wl_container_of(listener, l, listener); 138 l->count++; 139} 140 141TEST(new_resource) 142{ 143 const char *socket; 144 struct compositor compositor = { 0 }; 145 struct { 146 struct wl_display *display; 147 struct wl_callback *cb; 148 } client; 149 struct resource_listener resource_listener; 150 151 socket = setup_compositor(&compositor); 152 client.display = wl_display_connect(socket); 153 wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); 154 155 resource_listener.count = 0; 156 resource_listener.listener.notify = resource_created; 157 wl_client_add_resource_created_listener(compositor.client, 158 &resource_listener.listener); 159 160 client.cb = wl_display_sync(client.display); 161 wl_display_flush(client.display); 162 wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100); 163 164 assert(resource_listener.count == 1); 165 166 wl_callback_destroy(client.cb); 167 wl_display_disconnect(client.display); 168 cleanup_compositor(&compositor); 169 170 /* This is defined to be safe also after client destruction */ 171 wl_list_remove(&resource_listener.listener.link); 172} 173