apply tizen coding rule
[platform/core/uifw/libtdm.git] / client / tdm_client.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 <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <time.h>
44
45 #include "tdm_client.h"
46 #include "tdm_log.h"
47 #include "tdm_macro.h"
48 #include "tdm_list.h"
49 #include "tdm-client-protocol.h"
50
51 int tdm_debug;
52
53 typedef struct _tdm_private_client {
54         struct wl_display *display;
55         struct wl_registry *registry;
56         struct wl_tdm *tdm;
57         struct wl_tdm_client *tdm_client;
58         struct list_head vblank_list;
59 } tdm_private_client;
60
61 typedef struct _tdm_client_vblank_info {
62         struct list_head link;
63         struct wl_tdm_vblank *vblank;
64         tdm_client_vblank_handler func;
65         unsigned int req_sec;
66         unsigned int req_usec;
67         void *user_data;
68         int need_free;
69 } tdm_client_vblank_info;
70
71 static void
72 _tdm_client_cb_global(void *data, struct wl_registry *registry,
73                                           uint32_t name, const char *interface,
74                                           uint32_t version)
75 {
76         tdm_private_client *private_client = data;
77
78         if (strcmp(interface, "wl_tdm") == 0) {
79                 private_client->tdm =
80                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
81                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
82
83                 wl_display_flush(private_client->display);
84         }
85 }
86
87 static void
88 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
89 {
90 }
91
92 static const struct wl_registry_listener tdm_client_registry_listener = {
93         _tdm_client_cb_global,
94         _tdm_client_cb_global_remove
95 };
96
97 tdm_client*
98 tdm_client_create(tdm_client_error *error)
99 {
100         tdm_private_client *private_client;
101         const char *debug;
102
103         debug = getenv("TDM_DEBUG");
104         if (debug && (strstr(debug, "1")))
105                 tdm_debug = 1;
106
107         private_client = calloc(1, sizeof * private_client);
108         if (!private_client) {
109                 TDM_ERR("alloc failed");
110                 if (error)
111                         *error = TDM_CLIENT_ERROR_OUT_OF_MEMORY;
112                 return NULL;
113         }
114
115         private_client->display = wl_display_connect("tdm-socket");
116         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
117
118         private_client->registry = wl_display_get_registry(private_client->display);
119         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
120
121         wl_registry_add_listener(private_client->registry,
122                                                          &tdm_client_registry_listener, private_client);
123         wl_display_roundtrip(private_client->display);
124
125         /* check global objects */
126         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
127
128         LIST_INITHEAD(&private_client->vblank_list);
129
130         private_client->tdm_client = wl_tdm_create_client(private_client->tdm);
131         TDM_GOTO_IF_FAIL(private_client->tdm_client != NULL, create_failed);
132
133         if (error)
134                 *error = TDM_CLIENT_ERROR_NONE;
135
136         return (tdm_client*)private_client;
137 create_failed:
138         tdm_client_destroy((tdm_client*)private_client);
139         if (error)
140                 *error = TDM_CLIENT_ERROR_OPERATION_FAILED;
141         return NULL;
142 }
143
144 void
145 tdm_client_destroy(tdm_client *client)
146 {
147         tdm_private_client *private_client = (tdm_private_client*)client;
148         tdm_client_vblank_info *v = NULL, *vv = NULL;
149
150         if (!private_client)
151                 return;
152
153         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_client->vblank_list, link) {
154                 LIST_DEL(&v->link);
155                 wl_tdm_vblank_destroy(v->vblank);
156                 free(v);
157         }
158
159         if (private_client->tdm_client)
160                 wl_tdm_client_destroy(private_client->tdm_client);
161         if (private_client->tdm)
162                 wl_tdm_destroy(private_client->tdm);
163         if (private_client->registry)
164                 wl_registry_destroy(private_client->registry);
165         if (private_client->display)
166                 wl_display_disconnect(private_client->display);
167
168         free(private_client);
169 }
170
171 tdm_client_error
172 tdm_client_get_fd(tdm_client *client, int *fd)
173 {
174         tdm_private_client *private_client;
175
176         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
177         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
178
179         private_client = (tdm_private_client*)client;
180
181         *fd = wl_display_get_fd(private_client->display);
182         if (*fd < 0)
183                 return TDM_CLIENT_ERROR_OPERATION_FAILED;
184
185         return TDM_CLIENT_ERROR_NONE;
186 }
187
188 tdm_client_error
189 tdm_client_handle_events(tdm_client *client)
190 {
191         tdm_private_client *private_client;
192
193         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
194
195         private_client = (tdm_private_client*)client;
196
197         wl_display_dispatch(private_client->display);
198
199         return TDM_CLIENT_ERROR_NONE;
200 }
201
202 static void
203 _tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank,
204                                                    uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec)
205 {
206         tdm_client_vblank_info *vblank_info = (tdm_client_vblank_info*)data;
207
208         TDM_RETURN_IF_FAIL(vblank_info != NULL);
209
210         if (vblank_info->vblank != vblank)
211                 TDM_NEVER_GET_HERE();
212
213         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
214                         wl_proxy_get_id((struct wl_proxy *)vblank));
215
216         if (vblank_info->func)
217                 vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data);
218
219         if (vblank_info->need_free) {
220                 LIST_DEL(&vblank_info->link);
221                 free(vblank_info);
222         } else {
223                 vblank_info->need_free = 1;
224         }
225 }
226
227 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
228         _tdm_client_cb_vblank_done,
229 };
230
231 tdm_client_error
232 tdm_client_wait_vblank(tdm_client *client, char *name,
233                                            int sw_timer, int interval, int sync,
234                                            tdm_client_vblank_handler func, void *user_data)
235 {
236         tdm_private_client *private_client = (tdm_private_client*)client;
237         tdm_client_vblank_info *vblank_info;
238         struct timespec tp;
239         int ret = 0;
240
241         TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
242         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER);
243         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
244         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
245         TDM_RETURN_VAL_IF_FAIL(private_client->tdm_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER);
246
247         vblank_info = calloc(1, sizeof * vblank_info);
248         if (!vblank_info) {
249                 TDM_ERR("alloc failed");
250                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
251         }
252
253         clock_gettime(CLOCK_MONOTONIC, &tp);
254
255         vblank_info->req_sec = (unsigned int)tp.tv_sec;
256         vblank_info->req_usec = (unsigned int)(tp.tv_nsec / 1000);
257         vblank_info->need_free = (sync) ? 0 : 1;
258
259         vblank_info->vblank =
260                 wl_tdm_client_wait_vblank(private_client->tdm_client,
261                                                                   name, sw_timer, interval,
262                                                                   vblank_info->req_sec, vblank_info->req_usec);
263         if (!vblank_info->vblank) {
264                 TDM_ERR("couldn't create vblank resource");
265                 free(vblank_info);
266                 return TDM_CLIENT_ERROR_OUT_OF_MEMORY;
267         }
268
269         TDM_DBG("vblank_info(%p) wl_tbm_vblank@%d", vblank_info,
270                         wl_proxy_get_id((struct wl_proxy *)vblank_info->vblank));
271
272         wl_tdm_vblank_add_listener(vblank_info->vblank,
273                                                            &tdm_client_vblank_listener, vblank_info);
274
275         vblank_info->func = func;
276         vblank_info->user_data = user_data;
277         LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list);
278
279         if (!sync) {
280                 wl_display_flush(private_client->display);
281                 return TDM_CLIENT_ERROR_NONE;
282         }
283
284         while (ret != -1 && !vblank_info->need_free)
285                 ret = wl_display_dispatch(private_client->display);
286
287         clock_gettime(CLOCK_MONOTONIC, &tp);
288         TDM_DBG("block during %d us",
289                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
290                         - (vblank_info->req_sec * 1000000 + vblank_info->req_usec));
291
292         LIST_DEL(&vblank_info->link);
293         free(vblank_info);
294
295         return TDM_CLIENT_ERROR_NONE;
296 }