rename tdm_event to tdm_event_loop
[platform/core/uifw/libtdm.git] / src / tdm_event_loop.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43
44 #include <wayland-server-core.h>
45
46 struct _tdm_private_loop {
47         struct wl_display *wl_display;
48         struct wl_event_loop *wl_loop;
49
50         int backend_fd;
51         tdm_event_loop_source *backend_source;
52 };
53
54 typedef struct _tdm_event_loop_source_base
55 {
56         struct wl_event_source *wl_source;
57 } tdm_event_loop_source_base;
58
59 typedef struct _tdm_event_loop_source_fd
60 {
61         tdm_event_loop_source_base base;
62         tdm_private_display *private_display;
63         tdm_event_loop_fd_handler func;
64         void *user_data;
65 } tdm_event_loop_source_fd;
66
67 typedef struct _tdm_event_loop_source_timer
68 {
69         tdm_event_loop_source_base base;
70         tdm_private_display *private_display;
71         tdm_event_loop_timer_handler func;
72         void *user_data;
73 } tdm_event_loop_source_timer;
74
75 static tdm_error
76 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
77 {
78         tdm_private_display *private_display = (tdm_private_display*)user_data;
79         tdm_private_loop *private_loop;
80         tdm_func_display *func_display;
81
82         TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED);
83         TDM_RETURN_VAL_IF_FAIL(private_display->private_loop != NULL, TDM_ERROR_OPERATION_FAILED);
84
85         private_loop = private_display->private_loop;
86
87         if (tdm_debug_thread)
88                 TDM_INFO("backend fd(%d) event happens", private_loop->backend_fd);
89
90         func_display = &private_display->func_display;
91         if (!func_display->display_handle_events)
92                 return TDM_ERROR_NONE;
93
94         return func_display->display_handle_events(private_display->bdata);
95 }
96
97 INTERN tdm_error
98 tdm_event_loop_init(tdm_private_display *private_display)
99 {
100         tdm_private_loop *private_loop;
101
102         if (private_display->private_loop)
103                 return TDM_ERROR_NONE;
104
105         private_loop = calloc(1, sizeof *private_loop);
106         if (!private_loop) {
107                 TDM_ERR("alloc failed");
108                 return TDM_ERROR_OUT_OF_MEMORY;
109         }
110
111         private_loop->backend_fd = -1;
112
113         private_loop->wl_display = wl_display_create();
114         if (!private_loop->wl_display) {
115                 TDM_ERR("creating a wayland display failed");
116                 free(private_loop);
117                 return TDM_ERROR_OUT_OF_MEMORY;
118         }
119
120         private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
121         if (!private_loop->wl_loop) {
122                 TDM_ERR("no event loop");
123                 wl_display_destroy(private_loop->wl_display);
124                 free(private_loop);
125                 return TDM_ERROR_OUT_OF_MEMORY;
126         }
127
128         TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
129
130         private_display->private_loop = private_loop;
131
132         return TDM_ERROR_NONE;
133 }
134
135 INTERN void
136 tdm_event_loop_deinit(tdm_private_display *private_display)
137 {
138         if (!private_display->private_loop)
139                 return;
140
141         if (private_display->private_loop->backend_source)
142                 tdm_event_loop_source_remove(private_display->private_loop->backend_source);
143
144         if (private_display->private_loop->wl_display)
145                 wl_display_destroy(private_display->private_loop->wl_display);
146
147         free(private_display->private_loop);
148         private_display->private_loop = NULL;
149 }
150
151 INTERN void
152 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
153 {
154         tdm_private_loop *private_loop = private_display->private_loop;
155         tdm_func_display *func_display;
156         tdm_error ret;
157         int fd = -1;
158
159         TDM_RETURN_IF_FAIL(private_loop != NULL);
160
161         func_display = &private_display->func_display;
162         if (!func_display->display_get_fd) {
163                 TDM_INFO("TDM backend module won't offer a display fd");
164                 return;
165         }
166
167         ret = func_display->display_get_fd(private_display->bdata, &fd);
168         if (fd < 0) {
169                 TDM_WRN("TDM backend module returns fd(%d)", fd);
170                 return;
171         }
172
173         if (!func_display->display_handle_events) {
174                 TDM_ERR("no display_handle_events function");
175                 return;
176         }
177
178         private_loop->backend_source =
179                 tdm_event_loop_add_fd_handler(private_display, fd,
180                                               TDM_EVENT_LOOP_READABLE,
181                                               _tdm_event_loop_main_fd_handler,
182                                               private_display, &ret);
183         if (!private_loop->backend_source) {
184                 TDM_ERR("no backend fd(%d) source", fd);
185                 return;
186         }
187
188         private_loop->backend_fd = fd;
189
190         TDM_INFO("backend fd(%d) source created", private_loop->backend_fd);
191 }
192
193 INTERN int
194 tdm_event_loop_get_fd(tdm_private_display *private_display)
195 {
196         tdm_private_loop *private_loop = private_display->private_loop;
197
198         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
199
200         return wl_event_loop_get_fd(private_loop->wl_loop);
201 }
202
203 INTERN tdm_error
204 tdm_event_loop_dispatch(tdm_private_display *private_display)
205 {
206         tdm_private_loop *private_loop = private_display->private_loop;
207
208         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
209
210         if (tdm_debug_thread)
211                 TDM_INFO("dispatch");
212
213         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
214          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
215          * escaping polling.
216          */
217         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
218                 TDM_ERR("dispatch failed");
219
220         return TDM_ERROR_NONE;
221 }
222
223 INTERN tdm_error
224 tdm_event_loop_add_socket(tdm_private_display *private_display, const char *name)
225 {
226         tdm_private_loop *private_loop = private_display->private_loop;
227
228         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_OPERATION_FAILED);
229
230         if (wl_display_add_socket(private_loop->wl_display, name) < 0) {
231                 TDM_ERR("add socket(\"%s\") failed", name);
232                 return TDM_ERROR_OPERATION_FAILED;
233         }
234
235         return TDM_ERROR_NONE;
236 }
237
238 static int
239 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
240 {
241         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
242         tdm_event_loop_mask mask = 0;
243
244         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
245         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
246
247         if (wl_mask & WL_EVENT_READABLE)
248                 mask |= TDM_EVENT_LOOP_READABLE;
249         if (wl_mask & WL_EVENT_WRITABLE)
250                 mask |= TDM_EVENT_LOOP_WRITABLE;
251         if (wl_mask & WL_EVENT_HANGUP)
252                 mask |= TDM_EVENT_LOOP_HANGUP;
253         if (wl_mask & WL_EVENT_ERROR)
254                 mask |= TDM_EVENT_LOOP_ERROR;
255
256         fd_source->func(fd, mask, fd_source->user_data);
257
258         return 1;
259 }
260
261 EXTERN tdm_event_loop_source*
262 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
263                               tdm_event_loop_fd_handler func, void *user_data,
264                               tdm_error *error)
265 {
266         tdm_private_display *private_display;
267         tdm_private_loop *private_loop;
268         tdm_event_loop_source_fd *fd_source;
269         uint32_t wl_mask = 0;
270         tdm_error ret;
271
272         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
273         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
274         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
275
276         private_display = (tdm_private_display*)dpy;
277         private_loop = private_display->private_loop;
278         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
279         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
280
281         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
282         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
283
284         if (mask & TDM_EVENT_LOOP_READABLE)
285                 wl_mask |= WL_EVENT_READABLE;
286         if (mask & TDM_EVENT_LOOP_WRITABLE)
287                 wl_mask |= WL_EVENT_WRITABLE;
288
289         fd_source->base.wl_source =
290                 wl_event_loop_add_fd(private_loop->wl_loop,
291                                      fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
292         if (!fd_source->base.wl_source) {
293                 if (error)
294                         *error = TDM_ERROR_OUT_OF_MEMORY;
295                 free(fd_source);
296                 return NULL;
297         }
298
299         fd_source->private_display = private_display;
300         fd_source->func = func;
301         fd_source->user_data = user_data;
302
303         if (error)
304                 *error = TDM_ERROR_NONE;
305
306         return (tdm_event_loop_source*)fd_source;
307 }
308
309 EXTERN tdm_error
310 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
311 {
312         tdm_event_loop_source_fd *fd_source = source;
313         uint32_t wl_mask = 0;
314
315         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
316
317         if (mask & TDM_EVENT_LOOP_READABLE)
318                 wl_mask |= WL_EVENT_READABLE;
319         if (mask & TDM_EVENT_LOOP_WRITABLE)
320                 wl_mask |= WL_EVENT_WRITABLE;
321
322         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
323                 TDM_ERR("source update failed: %m");
324                 return TDM_ERROR_OPERATION_FAILED;
325         }
326
327         return TDM_ERROR_NONE;
328 }
329
330 static int
331 _tdm_event_loop_timer_func(void *data)
332 {
333         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
334
335         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
336         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
337
338         timer_source->func(timer_source->user_data);
339
340         return 1;
341 }
342
343 EXTERN tdm_event_loop_source*
344 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
345                                  void *user_data, tdm_error *error)
346 {
347         tdm_private_display *private_display;
348         tdm_private_loop *private_loop;
349         tdm_event_loop_source_timer *timer_source;
350         tdm_error ret;
351
352         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
353         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
354
355         private_display = (tdm_private_display*)dpy;
356         private_loop = private_display->private_loop;
357         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
358         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
359
360         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
361         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
362
363         timer_source->base.wl_source =
364                 wl_event_loop_add_timer(private_loop->wl_loop,
365                                         _tdm_event_loop_timer_func, timer_source);
366         if (!timer_source->base.wl_source) {
367                 if (error)
368                         *error = TDM_ERROR_OUT_OF_MEMORY;
369                 free(timer_source);
370                 return NULL;
371         }
372
373         timer_source->private_display = private_display;
374         timer_source->func = func;
375         timer_source->user_data = user_data;
376
377         if (error)
378                 *error = TDM_ERROR_NONE;
379
380         return (tdm_event_loop_source*)timer_source;
381 }
382
383 EXTERN tdm_error
384 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, int ms_delay)
385 {
386         tdm_event_loop_source_timer *timer_source = source;
387
388         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
389
390         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
391                 TDM_ERR("source update failed: %m");
392                 return TDM_ERROR_OPERATION_FAILED;
393         }
394
395         return TDM_ERROR_NONE;
396 }
397
398 EXTERN void
399 tdm_event_loop_source_remove(tdm_event_loop_source *source)
400 {
401         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
402
403         if (!base)
404                 return;
405
406         wl_event_source_remove(base->wl_source);
407
408         free(source);
409 }