seat: fix the typo. should handle a proper device type
[platform/core/uifw/libds-tizen.git] / src / libds / seat / seat.c
1 #include "config.h"
2
3 #define _POSIX_C_SOURCE 200809L
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "libds/log.h"
9 #include "seat_private.h"
10
11 #define SEAT_VERSION 7
12
13 static void seat_handle_bind(struct wl_client *wl_client, void *data,
14         uint32_t version, uint32_t id);
15 static void seat_handle_display_destroy(struct wl_listener *listener,
16         void *data);
17 static void seat_destroy(struct ds_seat *seat);
18 static struct ds_seat_client *seat_client_create(struct ds_seat *seat,
19         struct wl_client *wl_client);
20 static void seat_client_destroy(struct ds_seat_client *seat_client);
21 static void
22 seat_client_send_capabilities(struct ds_seat_client *seat_client);
23 static void seat_client_send_name(struct ds_seat_client *seat_client);
24
25 WL_EXPORT struct ds_seat *
26 ds_seat_create(struct wl_display *display, const char *name)
27 {
28     struct ds_seat *seat;
29
30     seat = calloc(1, sizeof *seat);
31     if (!seat)
32         return NULL;
33
34     if (!seat_pointer_init(seat)) {
35         ds_err("Failed to initialize pointer for seat(%s)", name);
36         goto err_ptr;
37     }
38
39     if (!seat_keyboard_init(seat)) {
40         ds_err("Failed to initialize keyboard for seat(%s)", name);
41         goto err_kbd;
42     }
43
44     if (!seat_touch_init(seat)) {
45         ds_err("Failed to initialize touch for seat(%s)", name);
46         goto err_touch;
47     }
48
49     seat->global = wl_global_create(display, &wl_seat_interface,
50             SEAT_VERSION, seat, seat_handle_bind);
51     if (!seat->global) {
52         ds_err("Failed to create wl_global for seat(%s)", name);
53         goto err_global;
54     }
55
56     seat->display = display;
57     seat->name = strdup(name);
58
59     wl_list_init(&seat->clients);
60
61     wl_signal_init(&seat->events.destroy);
62     wl_signal_init(&seat->events.pointer_grab_begin);
63     wl_signal_init(&seat->events.pointer_grab_end);
64     wl_signal_init(&seat->events.keyboard_grab_begin);
65     wl_signal_init(&seat->events.keyboard_grab_end);
66     wl_signal_init(&seat->events.touch_grab_begin);
67     wl_signal_init(&seat->events.touch_grab_end);
68
69     seat->display_destroy.notify = seat_handle_display_destroy;
70     wl_display_add_destroy_listener(display, &seat->display_destroy);
71
72     return seat;
73
74 err_global:
75     seat_touch_finish(seat);
76 err_touch:
77     seat_keyboard_finish(seat);
78 err_kbd:
79     seat_pointer_finish(seat);
80 err_ptr:
81     free(seat);
82
83     return NULL;
84 }
85
86 WL_EXPORT void
87 ds_seat_destroy(struct ds_seat *seat)
88 {
89     seat_destroy(seat);
90 }
91
92 WL_EXPORT void
93 ds_seat_set_capabilities(struct ds_seat *seat,
94         enum wl_seat_capability capabilities)
95 {
96     struct ds_seat_client *seat_client;
97
98     if (capabilities == seat->capabilities)
99         return;
100
101     seat->capabilities = capabilities;
102     seat->accumulated_capabilities |= capabilities;
103
104     wl_list_for_each(seat_client, &seat->clients, link) {
105         if (!(capabilities & WL_SEAT_CAPABILITY_POINTER)) {
106             seat_client_remove_all_pointer_resources(seat_client);
107         }
108         if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
109             seat_client_remove_all_keyboard_resources(seat_client);
110         }
111         if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
112             seat_client_remove_all_touch_resources(seat_client);
113         }
114
115         seat_client_send_capabilities(seat_client);
116     }
117 }
118
119 WL_EXPORT void
120 ds_seat_set_name(struct ds_seat *seat, const char *name)
121 {
122     struct ds_seat_client *seat_client;
123
124     free(seat->name);
125     seat->name = strdup(name);
126
127     wl_list_for_each(seat_client, &seat->clients, link) {
128         seat_client_send_name(seat_client);
129     }
130 }
131
132 WL_EXPORT void
133 ds_seat_add_destroy_listener(struct ds_seat *seat,
134         struct wl_listener *listener)
135 {
136     wl_signal_add(&seat->events.destroy, listener);
137 }
138
139 struct ds_seat_client *
140 seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client)
141 {
142     struct ds_seat_client *seat_client;
143
144     wl_list_for_each(seat_client, &seat->clients, link) {
145         if (seat_client->wl_client == wl_client)
146             return seat_client;
147     }
148
149     return NULL;
150 }
151
152 static struct ds_seat_client *
153 ds_seat_client_get_or_create(struct ds_seat *seat, struct wl_client *wl_client)
154 {
155     struct ds_seat_client *seat_client;
156
157     seat_client = seat_client_for_wl_client(seat, wl_client);
158     if (!seat_client) {
159         seat_client = seat_client_create(seat, wl_client);
160         if (!seat_client)
161             return NULL;
162
163         wl_list_insert(&seat->clients, &seat_client->link);
164     }
165
166     return seat_client;
167 }
168
169 static void
170 seat_handle_get_pointer(struct wl_client *wl_client,
171         struct wl_resource *resource, uint32_t id)
172 {
173     struct ds_seat_client *seat_client;
174
175     seat_client = wl_resource_get_user_data(resource);
176     if (!seat_client)
177         return;
178
179     if (!(seat_client->seat->accumulated_capabilities &
180                 WL_SEAT_CAPABILITY_POINTER)) {
181 #ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
182         wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
183                 "wl_seat.get_pointer called when no "
184                 "pointer capability has existed");
185 #endif
186         return;
187     }
188
189     seat_client_add_pointer_resource(seat_client,
190             wl_resource_get_version(resource), id);
191 }
192
193 static void
194 seat_handle_get_keyboard(struct wl_client *wl_client,
195         struct wl_resource *resource, uint32_t id)
196 {
197     struct ds_seat_client *seat_client;
198
199     seat_client = wl_resource_get_user_data(resource);
200     if (!seat_client)
201         return;
202
203     if (!(seat_client->seat->accumulated_capabilities &
204                 WL_SEAT_CAPABILITY_KEYBOARD)) {
205 #ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
206         wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
207                 "wl_seat.get_keyboard called when no "
208                 "keyboard capability has existed");
209 #endif
210         return;
211     }
212
213     seat_client_add_keyboard_resource(seat_client,
214             wl_resource_get_version(resource), id);
215 }
216
217 static void
218 seat_handle_get_touch(struct wl_client *wl_client,
219         struct wl_resource *resource, uint32_t id)
220 {
221     struct ds_seat_client *seat_client;
222
223     seat_client = wl_resource_get_user_data(resource);
224     if (!seat_client)
225         return;
226
227     if (!(seat_client->seat->accumulated_capabilities &
228                 WL_SEAT_CAPABILITY_TOUCH)) {
229 #ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
230         wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
231                 "wl_seat.get_touch called when no "
232                 "touch capability has existed");
233 #endif
234         return;
235     }
236
237     seat_client_add_touch_resource(seat_client,
238             wl_resource_get_version(resource), id);
239 }
240
241 static void
242 seat_handle_release(struct wl_client *wl_client, struct wl_resource *resource)
243 {
244     wl_resource_destroy(resource);
245 }
246
247 static const struct wl_seat_interface seat_impl =
248 {
249     .get_pointer = seat_handle_get_pointer,
250     .get_keyboard = seat_handle_get_keyboard,
251     .get_touch = seat_handle_get_touch,
252     .release = seat_handle_release,
253 };
254
255 static void
256 seat_client_handle_resource_destroy(struct wl_resource *resource)
257 {
258     struct ds_seat_client *seat_client;
259
260     seat_client = wl_resource_get_user_data(resource);
261     if (!seat_client)
262         return;
263
264     wl_list_remove(wl_resource_get_link(resource));
265     if (!wl_list_empty(&seat_client->resources))
266         return;
267
268     seat_client_destroy(seat_client);
269 }
270
271 static void
272 seat_handle_bind(struct wl_client *wl_client, void *data, uint32_t version,
273         uint32_t id)
274 {
275     struct ds_seat *seat = data;
276     struct ds_seat_client *seat_client;
277     struct wl_resource *resource;
278
279     resource = wl_resource_create(wl_client, &wl_seat_interface, version, id);
280     if (!resource) {
281         wl_client_post_no_memory(wl_client);
282         return;
283     }
284
285     seat_client = ds_seat_client_get_or_create(seat, wl_client);
286     if (!seat_client) {
287         wl_resource_destroy(resource);
288         wl_client_post_no_memory(wl_client);
289         return;
290     }
291
292     wl_resource_set_implementation(resource, &seat_impl,
293             seat_client, seat_client_handle_resource_destroy);
294
295     wl_list_insert(&seat_client->resources, wl_resource_get_link(resource));
296
297     wl_seat_send_capabilities(resource, seat->capabilities);
298
299     if (version >= WL_SEAT_NAME_SINCE_VERSION)
300         wl_seat_send_name(resource, seat->name);
301 }
302
303 static void
304 seat_handle_display_destroy(struct wl_listener *listener, void *data)
305 {
306     struct ds_seat *seat;
307
308     seat = wl_container_of(listener, seat, display_destroy);
309     seat_destroy(seat);
310 }
311
312 static void
313 seat_destroy(struct ds_seat *seat)
314 {
315     struct ds_seat_client *seat_client, *tmp;
316     struct wl_resource *resource, *next;
317
318     wl_signal_emit(&seat->events.destroy, seat);
319
320     wl_list_remove(&seat->display_destroy.link);
321
322     wl_list_for_each_safe(seat_client, tmp, &seat->clients, link) {
323         wl_resource_for_each_safe(resource, next, &seat_client->resources) {
324             wl_list_remove(wl_resource_get_link(resource));
325             wl_resource_set_user_data(resource, NULL);
326         }
327         seat_client_destroy(seat_client);
328     }
329
330     seat_pointer_finish(seat);
331     seat_keyboard_finish(seat);
332     seat_touch_finish(seat);
333
334     wl_global_destroy(seat->global);
335     free(seat->name);
336     free(seat);
337 }
338
339 static struct ds_seat_client *
340 seat_client_create(struct ds_seat *seat, struct wl_client *wl_client)
341 {
342     struct ds_seat_client *seat_client;
343
344     seat_client = calloc(1, sizeof *seat_client);
345     seat_client->seat = seat;
346     seat_client->wl_client = wl_client;
347
348     wl_list_init(&seat_client->resources);
349     wl_list_init(&seat_client->pointers);
350     wl_list_init(&seat_client->keyboards);
351     wl_list_init(&seat_client->touches);
352
353     wl_signal_init(&seat_client->events.destroy);
354
355     return seat_client;
356 }
357
358 static void
359 seat_client_destroy(struct ds_seat_client *seat_client)
360 {
361     wl_signal_emit(&seat_client->events.destroy, seat_client);
362
363     seat_client_remove_all_pointer_resources(seat_client);
364     seat_client_remove_all_keyboard_resources(seat_client);
365     seat_client_remove_all_touch_resources(seat_client);
366
367     wl_list_remove(&seat_client->link);
368
369     free(seat_client);
370 }
371
372 static void
373 seat_client_send_capabilities(struct ds_seat_client *seat_client)
374 {
375     struct wl_resource *resource;
376
377     wl_resource_for_each(resource, &seat_client->resources) {
378         wl_seat_send_capabilities(resource, seat_client->seat->capabilities);
379     }
380 }
381
382 static void
383 seat_client_send_name(struct ds_seat_client *seat_client)
384 {
385     struct wl_resource *resource;
386
387     wl_resource_for_each(resource, &seat_client->resources) {
388         wl_seat_send_name(resource, seat_client->seat->name);
389     }
390 }