seat: fix the typo. should handle a proper device type
[platform/core/uifw/libds-tizen.git] / src / libds / seat / seat_touch.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4
5 #include "libds/log.h"
6 #include "seat_private.h"
7
8 static const struct ds_touch_grab_interface default_touch_grab_iface;
9 static const struct wl_touch_interface touch_impl;
10
11 static void touch_handle_resource_destroy(struct wl_resource *resource);
12 static struct ds_touch_point *touch_point_create(struct ds_seat *seat,
13         int32_t touch_id, struct ds_surface *surface, double sx, double sy);
14 static void touch_point_destroy(struct ds_touch_point *point);
15 static void touch_point_clear_focus(struct ds_touch_point *point);
16 static struct ds_touch_point *seat_find_touch_point(struct ds_seat *seat,
17         int32_t touch_id);
18 static int seat_touch_num_points(struct ds_seat *seat);
19
20 WL_EXPORT uint32_t
21 ds_seat_touch_notify_down(struct ds_seat *seat, struct ds_surface *surface,
22         uint32_t time_msec, int32_t touch_id, double sx, double sy)
23 {
24     struct ds_seat_touch_grab *grab = seat->touch.grab;
25     struct ds_touch_point *point;
26     uint32_t serial;
27
28     // FIXME
29     // What if ds_touch_point is already exist associated with given touch_id?
30     point = touch_point_create(seat, touch_id, surface, sx, sy);
31     if (!point) {
32         ds_err("Could not create touch point");
33         return 0;
34     }
35
36     serial = grab->iface->down(grab, time_msec, point);
37     if (!serial) {
38         touch_point_destroy(point);
39         return 0;
40     }
41
42     if (serial && seat_touch_num_points(seat) == 1) {
43         seat->touch.grab_serial = serial;
44         seat->touch.grab_id = touch_id;
45     }
46
47     return serial;
48 }
49
50 WL_EXPORT void
51 ds_seat_touch_notify_up(struct ds_seat *seat, uint32_t time_msec,
52         int32_t touch_id)
53 {
54     struct ds_seat_touch_grab *grab = seat->touch.grab;
55     struct ds_touch_point *point;
56
57     clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
58
59     point = seat_find_touch_point(seat, touch_id);
60     if (!point)
61         return;
62
63     grab->iface->up(grab, time_msec, point);
64
65     touch_point_destroy(point);
66 }
67
68 WL_EXPORT void
69 ds_seat_touch_notify_motion(struct ds_seat *seat, uint32_t time_msec,
70         int32_t touch_id, double sx, double sy)
71 {
72     struct ds_seat_touch_grab *grab = seat->touch.grab;
73     struct ds_touch_point *point;
74
75     clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
76
77     point = seat_find_touch_point(seat, touch_id);
78     if (!point)
79         return;
80
81     point->sx = sx;
82     point->sy = sy;
83
84     grab->iface->motion(grab, time_msec, point);
85 }
86
87 WL_EXPORT void
88 ds_seat_touch_notify_frame(struct ds_seat *seat)
89 {
90     struct ds_seat_touch_grab *grab = seat->touch.grab;
91
92     if (grab->iface->frame)
93         grab->iface->frame(grab);
94 }
95
96 WL_EXPORT void
97 ds_seat_touch_add_grab_start_listener(struct ds_seat *seat,
98         struct wl_listener *listener)
99 {
100     wl_signal_add(&seat->events.touch_grab_begin, listener);
101 }
102
103 WL_EXPORT void
104 ds_seat_touch_end_grab_start_listener(struct ds_seat *seat,
105         struct wl_listener *listener)
106 {
107     wl_signal_add(&seat->events.touch_grab_end, listener);
108 }
109
110 uint32_t
111 ds_seat_touch_send_down(struct ds_seat *seat, struct ds_surface *surface,
112         uint32_t time_msec, int32_t touch_id, double sx, double sy)
113 {
114     struct ds_touch_point *point;
115     struct wl_resource *resource;
116     uint32_t serial;
117
118     point = seat_find_touch_point(seat, touch_id);
119     if (!point) {
120         ds_err("Got touch down for unknown touch point");
121         return 0;
122     }
123
124     serial = wl_display_next_serial(seat->display);
125     wl_resource_for_each(resource, &point->seat_client->touches) {
126         wl_touch_send_down(resource, serial, time_msec,
127                 ds_surface_get_wl_resource(surface), touch_id,
128                 wl_fixed_from_double(sx), wl_fixed_from_double(sy));
129     }
130
131     point->seat_client->needs_touch_frame = true;
132
133     return serial;
134 }
135
136 void
137 ds_seat_touch_send_up(struct ds_seat *seat, uint32_t time_msec,
138         int32_t touch_id)
139 {
140     struct ds_touch_point *point;
141     struct wl_resource *resource;
142     uint32_t serial;
143
144     point = seat_find_touch_point(seat, touch_id);
145     if (!point) {
146         ds_err("Got touch up for unknown touch point");
147         return;
148     }
149
150     serial = wl_display_next_serial(seat->display);
151     wl_resource_for_each(resource, &point->seat_client->touches)
152         wl_touch_send_up(resource, serial, time_msec, touch_id);
153
154     point->seat_client->needs_touch_frame = true;
155 }
156
157 void
158 ds_seat_touch_send_motion(struct ds_seat *seat, uint32_t time_msec,
159         int32_t touch_id, double sx, double sy)
160 {
161     struct ds_touch_point *point;
162     struct wl_resource *resource;
163
164     point = seat_find_touch_point(seat, touch_id);
165     if (!point) {
166         ds_err("Got touch motion for unknown touch point");
167         return;
168     }
169
170     wl_resource_for_each(resource, &point->seat_client->touches) {
171         wl_touch_send_motion(resource, time_msec, touch_id,
172                 wl_fixed_from_double(sx), wl_fixed_from_double(sy));
173     }
174
175     point->seat_client->needs_touch_frame = true;
176 }
177
178 void
179 ds_seat_touch_send_frame(struct ds_seat *seat)
180 {
181     struct ds_seat_client *seat_client;
182     struct wl_resource *resource;
183
184     wl_list_for_each(seat_client, &seat->clients, link) {
185         if (!seat_client->needs_touch_frame)
186             continue;
187
188         wl_resource_for_each(resource, &seat_client->touches)
189             wl_touch_send_frame(resource);
190
191         seat_client->needs_touch_frame = false;
192     }
193 }
194
195 bool
196 seat_touch_init(struct ds_seat *seat)
197 {
198     struct ds_seat_touch *touch = &seat->touch;
199     struct ds_seat_touch_grab *grab;
200
201     grab = calloc(1, sizeof *grab);
202     if (!grab)
203         return false;
204
205     grab->iface = &default_touch_grab_iface;
206     grab->seat = seat;
207
208     touch->default_grab = grab;
209     touch->grab = grab;
210     touch->seat = seat;
211
212     wl_list_init(&touch->touch_points);
213
214     return true;
215 }
216
217 void
218 seat_touch_finish(struct ds_seat *seat)
219 {
220     struct ds_seat_touch *touch = &seat->touch;
221     struct ds_touch_point *point;
222
223     wl_list_for_each(point, &touch->touch_points, link)
224         touch_point_clear_focus(point);
225
226     free(touch->default_grab);
227 }
228
229 void
230 seat_client_add_touch_resource(struct ds_seat_client *seat_client,
231         uint32_t version, uint32_t id)
232 {
233     struct wl_resource *resource;
234
235     resource = wl_resource_create(seat_client->wl_client,
236             &wl_touch_interface, version, id);
237     if (!resource) {
238         wl_client_post_no_memory(seat_client->wl_client);
239         return;
240     }
241
242     wl_resource_set_implementation(resource, &touch_impl, seat_client,
243             touch_handle_resource_destroy);
244
245     wl_list_insert(&seat_client->touches, wl_resource_get_link(resource));
246
247     if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH))
248         wl_resource_set_user_data(resource, NULL);
249 }
250
251 void
252 seat_client_remove_all_touch_resources(struct ds_seat_client *seat_client)
253 {
254     struct wl_resource *resource, *tmp;
255
256     wl_resource_for_each_safe(resource, tmp, &seat_client->touches) {
257         wl_list_remove(wl_resource_get_link(resource));
258         wl_resource_set_user_data(resource, NULL);
259     }
260 }
261
262 static uint32_t
263 default_touch_grab_iface_down(struct ds_seat_touch_grab *grab,
264         uint32_t time_msec, struct ds_touch_point *point)
265 {
266     return ds_seat_touch_send_down(grab->seat, point->surface, time_msec,
267             point->touch_id, point->sx, point->sy);
268 }
269
270 static void
271 default_touch_grab_iface_up(struct ds_seat_touch_grab *grab,
272         uint32_t time_msec, struct ds_touch_point *point)
273 {
274     ds_seat_touch_send_up(grab->seat, time_msec, point->touch_id);
275 }
276
277 static void
278 default_touch_grab_iface_motion(struct ds_seat_touch_grab *grab,
279         uint32_t time_msec, struct ds_touch_point *point)
280 {
281     if (!point->focused_surface || point->focused_surface == point->surface) {
282         ds_seat_touch_send_motion(grab->seat, time_msec, point->touch_id,
283                 point->sx, point->sy);
284     }
285 }
286
287 static void
288 default_touch_grab_iface_enter(struct ds_seat_touch_grab *grab,
289         uint32_t time_msec, struct ds_touch_point *point)
290 {
291     // not handled by default
292 }
293
294 static void
295 default_touch_grab_iface_frame(struct ds_seat_touch_grab *grab)
296 {
297     ds_seat_touch_send_frame(grab->seat);
298 }
299
300 static void
301 default_touch_grab_iface_cancel(struct ds_seat_touch_grab *grab)
302 {
303     // cannot be cancelled
304 }
305
306 static const struct ds_touch_grab_interface default_touch_grab_iface = {
307     .down = default_touch_grab_iface_down,
308     .up = default_touch_grab_iface_up,
309     .motion = default_touch_grab_iface_motion,
310     .enter = default_touch_grab_iface_enter,
311     .frame = default_touch_grab_iface_frame,
312     .cancel = default_touch_grab_iface_cancel,
313 };
314
315 static void
316 touch_handle_release(struct wl_client *client, struct wl_resource *resource)
317 {
318     wl_resource_destroy(resource);
319 }
320
321 static const struct wl_touch_interface touch_impl =
322 {
323     .release = touch_handle_release,
324 };
325
326 static void
327 touch_handle_resource_destroy(struct wl_resource *resource)
328 {
329     if (!wl_resource_get_user_data(resource))
330         return;
331
332     wl_list_remove(wl_resource_get_link(resource));
333 }
334
335 static void
336 touch_point_handle_surface_destroy(struct wl_listener *listener, void *data)
337 {
338     struct ds_touch_point *point;
339
340     point = wl_container_of(listener, point, surface_destroy);
341     point->surface = NULL;
342     wl_list_remove(&point->surface_destroy.link);
343     wl_list_init(&point->surface_destroy.link);
344 }
345
346 static void
347 touch_point_handle_client_destroy(struct wl_listener *listener, void *data)
348 {
349     struct ds_touch_point *point;
350
351     point = wl_container_of(listener, point, surface_destroy);
352     touch_point_destroy(point);
353 }
354
355 static struct ds_touch_point *
356 touch_point_create(struct ds_seat *seat, int32_t touch_id,
357         struct ds_surface *surface, double sx, double sy)
358 {
359     struct ds_touch_point *point;
360     struct ds_seat_client *seat_client;
361     struct wl_client *wl_client;
362
363     wl_client = wl_resource_get_client(ds_surface_get_wl_resource(surface));
364     seat_client = seat_client_for_wl_client(seat, wl_client);
365     if (!seat_client || wl_list_empty(&seat_client->touches))
366         return NULL;
367
368     point = calloc(1, sizeof *point);
369     if (!point)
370         return NULL;
371
372     point->touch_id = touch_id;
373     point->surface = surface;
374     point->seat_client = seat_client;
375     point->sx = sx;
376     point->sy = sy;
377
378     wl_signal_init(&point->events.destroy);
379
380     point->surface_destroy.notify = touch_point_handle_surface_destroy;
381     ds_surface_add_destroy_listener(surface, &point->surface_destroy);
382
383     point->client_destroy.notify = touch_point_handle_client_destroy;
384     wl_signal_add(&seat_client->events.destroy, &point->client_destroy);
385
386     wl_list_insert(&seat->touch.touch_points, &point->link);
387
388     return point;
389 }
390
391 static void
392 touch_point_destroy(struct ds_touch_point *point)
393 {
394     wl_signal_emit(&point->events.destroy, point);
395
396     touch_point_clear_focus(point);
397
398     wl_list_remove(&point->surface_destroy.link);
399     wl_list_remove(&point->client_destroy.link);
400     wl_list_remove(&point->link);
401     free(point);
402 }
403
404 static void
405 touch_point_clear_focus(struct ds_touch_point *point)
406 {
407     if (!point->focused_surface)
408         return;
409
410     wl_list_remove(&point->focused_surface_destroy.link);
411     point->focused_client = NULL;
412     point->focused_surface = NULL;
413 }
414
415 static struct ds_touch_point *seat_find_touch_point(struct ds_seat *seat,
416         int32_t touch_id)
417 {
418     struct ds_touch_point *point;
419
420     wl_list_for_each(point, &seat->touch.touch_points, link) {
421         if (point->touch_id == touch_id)
422             return point;
423     }
424
425     return NULL;
426 }
427
428 static int
429 seat_touch_num_points(struct ds_seat *seat)
430 {
431     return wl_list_length(&seat->touch.touch_points);
432 }