1 /*
2  * Copyright © 2016 Quentin "Sardem FF7" Glidic
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "config.h"
25 
26 #include <wayland-server.h>
27 
28 #include <libweston/libweston.h>
29 #include <libweston/zalloc.h>
30 
31 #include <libweston-desktop/libweston-desktop.h>
32 #include "internal.h"
33 
34 struct weston_desktop_client {
35 	struct weston_desktop *desktop;
36 	struct wl_client *client;
37 	struct wl_resource *resource;
38 	struct wl_list surface_list;
39 	uint32_t ping_serial;
40 	struct wl_event_source *ping_timer;
41 	struct wl_signal destroy_signal;
42 };
43 
44 void
weston_desktop_client_add_destroy_listener(struct weston_desktop_client * client,struct wl_listener * listener)45 weston_desktop_client_add_destroy_listener(struct weston_desktop_client *client,
46 					   struct wl_listener *listener)
47 {
48 	wl_signal_add(&client->destroy_signal, listener);
49 }
50 
51 static void
weston_desktop_client_destroy(struct wl_resource * resource)52 weston_desktop_client_destroy(struct wl_resource *resource)
53 {
54 	struct weston_desktop_client *client =
55 		wl_resource_get_user_data(resource);
56 	struct wl_list *list = &client->surface_list;
57 	struct wl_list *link, *tmp;
58 
59 	wl_signal_emit(&client->destroy_signal, client);
60 
61 	for (link = list->next, tmp = link->next;
62 	     link != list;
63 	     link = tmp, tmp = link->next) {
64 		wl_list_remove(link);
65 		wl_list_init(link);
66 	}
67 
68 	if (client->ping_timer != NULL)
69 		wl_event_source_remove(client->ping_timer);
70 
71 	free(client);
72 }
73 
74 static int
weston_desktop_client_ping_timeout(void * user_data)75 weston_desktop_client_ping_timeout(void *user_data)
76 {
77 	struct weston_desktop_client *client = user_data;
78 
79 	weston_desktop_api_ping_timeout(client->desktop, client);
80 	return 1;
81 }
82 
83 struct weston_desktop_client *
weston_desktop_client_create(struct weston_desktop * desktop,struct wl_client * wl_client,wl_dispatcher_func_t dispatcher,const struct wl_interface * interface,const void * implementation,uint32_t version,uint32_t id)84 weston_desktop_client_create(struct weston_desktop *desktop,
85 			     struct wl_client *wl_client,
86 			     wl_dispatcher_func_t dispatcher,
87 			     const struct wl_interface *interface,
88 			     const void *implementation, uint32_t version,
89 			     uint32_t id)
90 {
91 	struct weston_desktop_client *client;
92 	struct wl_display *display;
93 	struct wl_event_loop *loop;
94 
95 	client = zalloc(sizeof(struct weston_desktop_client));
96 	if (client == NULL) {
97 		if (wl_client != NULL)
98 			wl_client_post_no_memory(wl_client);
99 		return NULL;
100 	}
101 
102 	client->desktop = desktop;
103 	client->client = wl_client;
104 
105 	wl_list_init(&client->surface_list);
106 	wl_signal_init(&client->destroy_signal);
107 
108 	if (wl_client == NULL)
109 		return client;
110 
111 	client->resource = wl_resource_create(wl_client, interface, version, id);
112 	if (client->resource == NULL) {
113 		wl_client_post_no_memory(wl_client);
114 		free(client);
115 		return NULL;
116 	}
117 
118 	if (dispatcher != NULL)
119 		wl_resource_set_dispatcher(client->resource, dispatcher,
120 					   weston_desktop_client_destroy, client,
121 					   weston_desktop_client_destroy);
122 	else
123 		wl_resource_set_implementation(client->resource, implementation,
124 					       client,
125 					       weston_desktop_client_destroy);
126 
127 
128 	display = wl_client_get_display(client->client);
129 	loop = wl_display_get_event_loop(display);
130 	client->ping_timer =
131 		wl_event_loop_add_timer(loop,
132 					weston_desktop_client_ping_timeout,
133 					client);
134 	if (client->ping_timer == NULL)
135 		wl_client_post_no_memory(wl_client);
136 
137 	return client;
138 }
139 
140 struct weston_desktop *
weston_desktop_client_get_desktop(struct weston_desktop_client * client)141 weston_desktop_client_get_desktop(struct weston_desktop_client *client)
142 {
143 	return client->desktop;
144 }
145 
146 struct wl_resource *
weston_desktop_client_get_resource(struct weston_desktop_client * client)147 weston_desktop_client_get_resource(struct weston_desktop_client *client)
148 {
149 	return client->resource;
150 }
151 
152 struct wl_list *
weston_desktop_client_get_surface_list(struct weston_desktop_client * client)153 weston_desktop_client_get_surface_list(struct weston_desktop_client *client)
154 {
155 	return &client->surface_list;
156 }
157 
158 WL_EXPORT struct wl_client *
weston_desktop_client_get_client(struct weston_desktop_client * client)159 weston_desktop_client_get_client(struct weston_desktop_client *client)
160 {
161 	return client->client;
162 }
163 
164 WL_EXPORT void
weston_desktop_client_for_each_surface(struct weston_desktop_client * client,void (* callback)(struct weston_desktop_surface * surface,void * user_data),void * user_data)165 weston_desktop_client_for_each_surface(struct weston_desktop_client *client,
166 				       void (*callback)(struct weston_desktop_surface *surface, void *user_data),
167 				       void *user_data)
168 {
169 	struct wl_list *list = &client->surface_list;
170 	struct wl_list *link;
171 
172 	for (link = list->next; link != list; link = link->next)
173 		callback(weston_desktop_surface_from_client_link(link),
174 			 user_data);
175 }
176 
177 WL_EXPORT int
weston_desktop_client_ping(struct weston_desktop_client * client)178 weston_desktop_client_ping(struct weston_desktop_client *client)
179 {
180 	struct weston_desktop_surface *surface =
181 		weston_desktop_surface_from_client_link(client->surface_list.next);
182 	const struct weston_desktop_surface_implementation *implementation =
183 		weston_desktop_surface_get_implementation(surface);
184 	void *implementation_data =
185 		weston_desktop_surface_get_implementation_data(surface);
186 
187 	if (implementation->ping == NULL)
188 		return -1;
189 
190 	if (client->ping_serial != 0)
191 		return 1;
192 
193 	client->ping_serial =
194 		wl_display_next_serial(wl_client_get_display(client->client));
195 	wl_event_source_timer_update(client->ping_timer, 10000);
196 
197 	implementation->ping(surface, client->ping_serial, implementation_data);
198 
199 	return 0;
200 }
201 
202 void
weston_desktop_client_pong(struct weston_desktop_client * client,uint32_t serial)203 weston_desktop_client_pong(struct weston_desktop_client *client, uint32_t serial)
204 {
205 	if (client->ping_serial != serial)
206 		return;
207 
208 	weston_desktop_api_pong(client->desktop, client);
209 
210 	wl_event_source_timer_update(client->ping_timer, 0);
211 	client->ping_serial = 0;
212 }
213