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