common: fix syntax error
[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 <boram1288.park@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 #include <strings.h>
45 #include <poll.h>
46
47 #include <tdm-client-protocol.h>
48
49 #include "tdm_client.h"
50 #include "tdm_log.h"
51 #include "tdm_macro.h"
52 #include "tdm_list.h"
53 #include "tdm.h"
54 #include "tdm_private.h"
55
56 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
57
58 typedef struct _tdm_private_client {
59         pthread_mutex_t lock;
60
61         struct wl_display *display;
62         struct wl_event_queue *queue;
63         struct wl_registry *registry;
64         struct wl_tdm *tdm;
65         struct list_head output_list;
66
67         unsigned int enable_ttrace;
68         unsigned int stamp;
69
70         tdm_private_client_vblank *temp_vblank;
71 } tdm_private_client;
72
73 typedef struct _tdm_private_client_output {
74         tdm_private_client *private_client;
75
76         char name[TDM_NAME_LEN];
77         struct wl_tdm_output *output;
78         int width;
79         int height;
80         int refresh;
81         tdm_output_conn_status connection;
82         tdm_output_dpms dpms;
83         struct list_head vblank_list;
84         struct list_head change_handler_list;
85
86         unsigned int req_id;
87         unsigned int watch_output_changes;
88
89         struct list_head link;
90 } tdm_private_client_output;
91
92 struct _tdm_private_client_vblank {
93         tdm_private_client_output *private_output;
94
95         struct wl_tdm_vblank *vblank;
96         struct list_head wait_list;
97
98         char name[TDM_NAME_LEN];
99         unsigned int sync;
100         unsigned int fps;
101         int offset;
102         unsigned int enable_fake;
103         unsigned int enable_ttrace;
104
105         unsigned int started;
106         unsigned int stamp;
107
108         double req_time;
109         double last_time;
110
111         struct list_head link;
112 };
113
114 typedef struct _tdm_client_output_handler_info {
115         tdm_private_client_output *private_output;
116
117         tdm_client_output_change_handler func;
118         void *user_data;
119
120         struct list_head link;
121         struct list_head call_link;
122 } tdm_client_output_handler_info;
123
124 typedef struct _tdm_client_wait_info {
125         tdm_private_client_vblank *private_vblank;
126
127         tdm_client_vblank_handler func;
128         void *user_data;
129
130         unsigned int req_id;
131         double req_time;
132         int need_free;
133
134         struct list_head link;
135         struct list_head call_link;
136 } tdm_client_wait_info;
137
138 static unsigned int
139 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
140 {
141         uint32_t ec, id;
142         const struct wl_interface *intf;
143         int err;
144
145         err = wl_display_get_error(private_client->display);
146         if (!err)
147                 return false;
148
149         if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
150                 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
151                 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
152                                 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
153         } else {
154                 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
155         }
156
157         return true;
158 }
159
160 #define CHECK_WL_PROTOCOL_ERROR(pc)  _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
161
162 static void
163 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
164 {
165         tdm_private_client_vblank *private_vblank = data;
166         tdm_private_client *private_client;
167
168         TDM_RETURN_IF_FAIL(private_vblank != NULL);
169
170         private_vblank->stamp = stamp;
171
172         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
173         private_client = private_vblank->private_output->private_client;
174
175         private_client->stamp = stamp;
176 }
177
178 /* LCOV_EXCL_START */
179 static void
180 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
181                                                    uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
182                                                    uint32_t tv_usec, uint32_t error)
183 {
184         tdm_private_client_vblank *private_vblank = data;
185         tdm_private_client *private_client;
186         tdm_client_wait_info *w = NULL, *wait_info = NULL;
187
188         TDM_RETURN_IF_FAIL(private_vblank != NULL);
189
190         private_client = private_vblank->private_output->private_client;
191
192         private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
193
194         TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
195                         private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
196
197         LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
198                 if (w->req_id != req_id)
199                         continue;
200
201                 wait_info = w;
202                 break;
203         }
204
205         if (!wait_info) {
206                 TDM_ERR("no wait infomation for req_id(%d)", req_id);
207                 return;
208         }
209
210         if (private_vblank->enable_ttrace)
211                 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
212
213         if (wait_info->req_time >= private_vblank->last_time)
214                 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
215
216         if (wait_info->need_free)
217                 LIST_DEL(&wait_info->link);
218
219         if (wait_info->func) {
220                 pthread_mutex_unlock(&private_client->lock);
221                 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
222                 pthread_mutex_lock(&private_client->lock);
223         }
224
225         if (wait_info->need_free)
226                 free(w);
227         else
228                 wait_info->need_free = 1;
229 }
230 /* LCOV_EXCL_STOP */
231
232 /* LCOV_EXCL_START */
233 static void
234 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
235 {
236         tdm_private_client_vblank *private_vblank = data;
237         tdm_private_client *private_client;
238
239         TDM_RETURN_IF_FAIL(private_vblank != NULL);
240
241         private_vblank->enable_ttrace = enable;
242
243         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
244         private_client = private_vblank->private_output->private_client;
245
246         private_client->enable_ttrace = enable;
247 }
248 /* LCOV_EXCL_STOP */
249
250 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
251         _tdm_client_vblank_cb_stamp,
252         _tdm_client_vblank_cb_done,
253         _tdm_client_vblank_cb_ttrace,
254 };
255
256 static void
257 _tdm_client_output_destroy(tdm_private_client_output *private_output)
258 {
259         tdm_private_client_vblank *v = NULL, *vv = NULL;
260         tdm_client_output_handler_info *h = NULL, *hh = NULL;
261
262         LIST_DEL(&private_output->link);
263
264         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
265                 TDM_ERR("vblanks SHOULD be destroyed first!");
266                 LIST_DEL(&v->link);
267                 v->private_output = NULL;
268         }
269
270         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
271                 LIST_DEL(&h->link);
272                 free(h);
273         }
274
275         wl_tdm_output_destroy(private_output->output);
276
277         free(private_output);
278 }
279
280 static void
281 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
282                                                    uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
283 {
284         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
285
286         TDM_RETURN_IF_FAIL(private_output != NULL);
287
288         private_output->width = width;
289         private_output->height = height;
290         private_output->refresh = refresh;
291
292         if (error != TDM_ERROR_NONE)
293                 TDM_INFO("mode event error: %d", error);
294
295         TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
296                         private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
297                         width, height, refresh);
298 }
299
300 static void
301 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
302 {
303         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
304         tdm_private_client *private_client;
305         tdm_client_output_handler_info *h = NULL, *hh = NULL;
306         tdm_value v;
307         struct list_head call_list;
308
309         TDM_RETURN_IF_FAIL(private_output != NULL);
310
311         private_client = private_output->private_client;
312
313         if (private_output->connection == value)
314                 return;
315
316         private_output->connection = value;
317
318         if (error != TDM_ERROR_NONE)
319                 TDM_INFO("connection event error: %d", error);
320
321         TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
322                         private_output,
323                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
324                         value);
325
326         LIST_INITHEAD(&call_list);
327
328         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
329                 LIST_ADDTAIL(&h->call_link, &call_list);
330         }
331
332         v.u32 = value;
333         pthread_mutex_unlock(&private_client->lock);
334         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
335                 if (h->func)
336                         h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
337         }
338         pthread_mutex_lock(&private_client->lock);
339 }
340
341 static void
342 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
343 {
344         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
345         tdm_private_client *private_client;
346         tdm_client_output_handler_info *h = NULL, *hh = NULL;
347         tdm_value v;
348         struct list_head call_list;
349
350         TDM_RETURN_IF_FAIL(private_output != NULL);
351
352         private_client = private_output->private_client;
353
354         /* If value is extended value, we handle it as DPMS on in client side
355          * The extended DPMS value is valid only in server side.
356          * Or, need to export to client side also?
357          */
358         if (value > TDM_OUTPUT_DPMS_OFF)
359                 value = TDM_OUTPUT_DPMS_ON;
360
361         if (private_output->dpms == value)
362                 return;
363
364         private_output->dpms = value;
365
366         if (error != TDM_ERROR_NONE)
367                 TDM_INFO("dpms event error: %d", error);
368
369         TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
370                         private_output,
371                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
372                         value);
373
374         LIST_INITHEAD(&call_list);
375
376         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
377                 LIST_ADDTAIL(&h->call_link, &call_list);
378         }
379
380         v.u32 = value;
381         pthread_mutex_unlock(&private_client->lock);
382         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
383                 if (h->func)
384                         h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
385         }
386         pthread_mutex_lock(&private_client->lock);
387 }
388
389 static const struct wl_tdm_output_listener tdm_client_output_listener = {
390         _tdm_client_output_cb_mode,
391         _tdm_client_output_cb_connection,
392         _tdm_client_output_cb_dpms,
393 };
394
395 static void
396 _tdm_client_cb_global(void *data, struct wl_registry *registry,
397                                           uint32_t name, const char *interface,
398                                           uint32_t version)
399 {
400         tdm_private_client *private_client = data;
401
402         if (strncmp(interface, "wl_tdm", 6) == 0) {
403                 private_client->tdm =
404                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
405                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
406
407                 wl_display_flush(private_client->display);
408         }
409 }
410
411 /* LCOV_EXCL_START */
412 static void
413 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
414 {
415 }
416 /* LCOV_EXCL_STOP */
417
418 static const struct wl_registry_listener tdm_client_registry_listener = {
419         _tdm_client_cb_global,
420         _tdm_client_cb_global_remove
421 };
422
423 tdm_client*
424 tdm_client_create(tdm_error *error)
425 {
426         tdm_private_client *private_client;
427
428         private_client = calloc(1, sizeof *private_client);
429         if (!private_client) {
430                 /* LCOV_EXCL_START */
431
432                 TDM_ERR("alloc failed");
433                 if (error)
434                         *error = TDM_ERROR_OUT_OF_MEMORY;
435                 return NULL;
436
437                 /* LCOV_EXCL_STOP */
438         }
439
440         if (pthread_mutex_init(&private_client->lock, NULL)) {
441                 TDM_ERR("mutex init failed: %m");
442                 free(private_client);
443                 if (error)
444                         *error = TDM_ERROR_OUT_OF_MEMORY;
445                 return NULL;
446         }
447
448         LIST_INITHEAD(&private_client->output_list);
449
450         private_client->display = wl_display_connect("tdm-socket");
451         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
452
453         private_client->queue = wl_display_create_queue(private_client->display);
454         TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
455
456         private_client->registry = wl_display_get_registry(private_client->display);
457         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
458
459         wl_registry_add_listener(private_client->registry,
460                                                          &tdm_client_registry_listener, private_client);
461         wl_display_roundtrip(private_client->display);
462
463         if (CHECK_WL_PROTOCOL_ERROR(private_client))
464                 goto create_failed;
465
466         /* check global objects */
467         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
468
469         if (error)
470                 *error = TDM_ERROR_NONE;
471
472         return (tdm_client*)private_client;
473 create_failed:
474         tdm_client_destroy((tdm_client*)private_client);
475         if (error)
476                 *error = TDM_ERROR_OPERATION_FAILED;
477         return NULL;
478 }
479
480 void
481 tdm_client_destroy(tdm_client *client)
482 {
483         tdm_private_client *private_client = (tdm_private_client*)client;
484         tdm_private_client_output *o = NULL, *oo = NULL;
485
486         if (!private_client)
487                 return;
488
489         pthread_mutex_lock(&private_client->lock);
490
491         if (private_client->temp_vblank) {
492                 pthread_mutex_unlock(&private_client->lock);
493                 tdm_client_vblank_destroy(private_client->temp_vblank);
494                 pthread_mutex_lock(&private_client->lock);
495         }
496
497         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
498                 _tdm_client_output_destroy(o);
499         }
500
501         if (private_client->tdm)
502                 wl_tdm_destroy(private_client->tdm);
503         if (private_client->registry)
504                 wl_registry_destroy(private_client->registry);
505         if (private_client->queue)
506                 wl_event_queue_destroy(private_client->queue);
507         if (private_client->display)
508                 wl_display_disconnect(private_client->display);
509
510         pthread_mutex_unlock(&private_client->lock);
511         pthread_mutex_destroy(&private_client->lock);
512
513         free(private_client);
514 }
515
516 tdm_error
517 tdm_client_get_fd(tdm_client *client, int *fd)
518 {
519         tdm_private_client *private_client;
520
521         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
522         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
523
524         private_client = (tdm_private_client*)client;
525
526         pthread_mutex_lock(&private_client->lock);
527
528         *fd = wl_display_get_fd(private_client->display);
529
530         pthread_mutex_unlock(&private_client->lock);
531
532         if (*fd < 0)
533                 return TDM_ERROR_OPERATION_FAILED;
534
535         return TDM_ERROR_NONE;
536 }
537
538 tdm_error
539 tdm_client_handle_events(tdm_client *client)
540 {
541         tdm_private_client *private_client;
542
543         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
544
545         /* LCOV_EXCL_START */
546         private_client = (tdm_private_client*)client;
547
548         pthread_mutex_lock(&private_client->lock);
549
550         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
551                 pthread_mutex_unlock(&private_client->lock);
552                 return TDM_ERROR_PROTOCOL_ERROR;
553         }
554
555         if (private_client->enable_ttrace)
556                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
557
558         wl_display_dispatch(private_client->display);
559
560         if (private_client->enable_ttrace)
561                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
562
563         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
564                 pthread_mutex_unlock(&private_client->lock);
565                 return TDM_ERROR_PROTOCOL_ERROR;
566         }
567
568         pthread_mutex_unlock(&private_client->lock);
569
570         return TDM_ERROR_NONE;
571         /* LCOV_EXCL_STOP */
572 }
573
574 static int
575 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
576 {
577         int ret;
578         struct pollfd pfd[1];
579
580         pfd[0].fd = wl_display_get_fd(display);
581         pfd[0].events = events;
582         do {
583                 ret = poll(pfd, 1, timeout);
584         } while (ret == -1 && errno == EINTR);
585
586         return ret;
587 }
588
589 static tdm_error
590 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
591 {
592         int ret;
593         struct wl_display *display = private_client->display;
594
595         if (wl_display_prepare_read(display) == -1) {
596                 if (wl_display_dispatch_pending(display) > 0)
597                         return TDM_ERROR_NONE;
598                 else
599                         return TDM_ERROR_OPERATION_FAILED;
600         }
601
602         while (true) {
603                 ret = wl_display_flush(display);
604
605                 if (ret != -1 || errno != EAGAIN)
606                         break;
607
608                 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
609                         wl_display_cancel_read(display);
610                         TDM_ERR("_tdm_client_poll failed");
611                         return TDM_ERROR_OPERATION_FAILED;
612                 }
613         }
614
615         /* Don't stop if flushing hits an EPIPE; continue so we can read any
616          * protocol error that may have triggered it. */
617         if (ret < 0 && errno != EPIPE) {
618                 TDM_ERR("ret(%d) errno(%d)", ret, errno);
619                 wl_display_cancel_read(display);
620                 return TDM_ERROR_OPERATION_FAILED;
621         }
622
623         ret = _tdm_client_poll(display, POLLIN, timeout);
624         if (ret <= 0) {
625                 wl_display_cancel_read(display);
626                 if (ret == 0) {
627                         TDM_ERR("_tdm_client_poll timeout.");
628                         return TDM_ERROR_TIMEOUT;
629                 } else {
630                         TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
631                         return TDM_ERROR_OPERATION_FAILED;
632                 }
633         }
634
635         if (wl_display_read_events(display) == -1) {
636                 TDM_ERR("wl_display_read_events failed");
637                 return TDM_ERROR_OPERATION_FAILED;
638         }
639
640         ret = wl_display_dispatch_pending(display);
641
642         if (ret < 0) {
643                 TDM_ERR("_tdm_client_dispatch_timeout failed");
644                 return TDM_ERROR_OPERATION_FAILED;
645         }
646
647         return TDM_ERROR_NONE;
648 }
649
650 tdm_error
651 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
652 {
653         tdm_private_client *private_client;
654         tdm_error ret;
655         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
656
657         private_client = (tdm_private_client*)client;
658
659         pthread_mutex_lock(&private_client->lock);
660
661         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
662                 pthread_mutex_unlock(&private_client->lock);
663                 return TDM_ERROR_PROTOCOL_ERROR;
664         }
665
666         if (private_client->enable_ttrace)
667                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
668
669         ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
670
671         if (private_client->enable_ttrace)
672                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
673
674         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
675                 pthread_mutex_unlock(&private_client->lock);
676                 return TDM_ERROR_PROTOCOL_ERROR;
677         }
678
679         pthread_mutex_unlock(&private_client->lock);
680
681         return ret;
682 }
683
684 typedef struct _tdm_client_vblank_temp {
685         tdm_client_vblank_handler2 func;
686         void *user_data;
687 } tdm_client_vblank_temp;
688
689 /* LCOV_EXCL_START */
690 static void
691 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
692                                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
693 {
694         tdm_client_vblank_temp *vblank_temp = user_data;
695
696         TDM_RETURN_IF_FAIL(vblank_temp != NULL);
697         TDM_RETURN_IF_FAIL(vblank != NULL);
698
699         if (vblank_temp->func)
700                 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
701
702         free(vblank_temp);
703 }
704 /* LCOV_EXCL_STOP */
705
706 /* LCOV_EXCL_START */ /* deprecated */
707 tdm_error
708 tdm_client_wait_vblank(tdm_client *client, char *name,
709                                            int sw_timer, int interval, int sync,
710                                            tdm_client_vblank_handler2 func, void *user_data)
711 {
712         tdm_private_client *private_client = (tdm_private_client*)client;
713         tdm_client_output *output;
714         tdm_client_vblank_temp *vblank_temp;
715         tdm_error ret;
716
717         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
718         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
719         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
720
721         if (CHECK_WL_PROTOCOL_ERROR(private_client))
722                 return TDM_ERROR_PROTOCOL_ERROR;
723
724         if (!private_client->temp_vblank) {
725                 output = tdm_client_get_output(client, name, &ret);
726                 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
727
728                 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
729                 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
730         }
731
732         tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
733         tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
734
735         vblank_temp = calloc(1, sizeof *vblank_temp);
736         TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
737
738         vblank_temp->func = func;
739         vblank_temp->user_data = user_data;
740
741         return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
742 }
743 /* LCOV_EXCL_STOP */
744
745 tdm_client_output*
746 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
747 {
748         tdm_private_client *private_client;
749         tdm_private_client_output *private_output = NULL;
750         struct wl_proxy *wrapper;
751
752         if (error)
753                 *error = TDM_ERROR_NONE;
754
755         if (!client) {
756                 TDM_ERR("'!client' failed");
757                 if (error)
758                         *error = TDM_ERROR_INVALID_PARAMETER;
759                 return NULL;
760         }
761
762         private_client = (tdm_private_client*)client;
763
764         pthread_mutex_lock(&private_client->lock);
765
766         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
767                 if (error)
768                         *error = TDM_ERROR_PROTOCOL_ERROR;
769                 pthread_mutex_unlock(&private_client->lock);
770                 return NULL;
771         }
772
773         if (!name) {
774                 name = "primary";
775         } else if (strncmp(name, "primary", 7) && strncmp(name, "default", 7)) {
776                 if (error)
777                         *error = TDM_ERROR_INVALID_PARAMETER;
778                 pthread_mutex_unlock(&private_client->lock);
779                 return NULL;
780         }
781
782         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
783                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
784                         pthread_mutex_unlock(&private_client->lock);
785                         return (tdm_client_output*)private_output;
786                 }
787         }
788
789         wrapper = wl_proxy_create_wrapper(private_client->tdm);
790         if (!wrapper) {
791                 TDM_ERR("create output_wrapper failed");
792                 if (error)
793                         *error = TDM_ERROR_OUT_OF_MEMORY;
794                 pthread_mutex_unlock(&private_client->lock);
795                 return NULL;
796         }
797
798         wl_proxy_set_queue(wrapper, private_client->queue);
799
800         private_output = calloc(1, sizeof *private_output);
801         if (!private_output) {
802                 /* LCOV_EXCL_START */
803                 wl_proxy_wrapper_destroy(wrapper);
804                 TDM_ERR("alloc failed");
805                 if (error)
806                         *error = TDM_ERROR_OUT_OF_MEMORY;
807                 pthread_mutex_unlock(&private_client->lock);
808                 return NULL;
809
810                 /* LCOV_EXCL_STOP */
811         }
812
813         private_output->private_client = private_client;
814
815         snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
816         private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
817         wl_proxy_wrapper_destroy(wrapper);
818         if (!private_output->output) {
819                 /* LCOV_EXCL_START */
820
821                 TDM_ERR("couldn't create output resource");
822                 free(private_output);
823                 if (error)
824                         *error = TDM_ERROR_OUT_OF_MEMORY;
825                 pthread_mutex_unlock(&private_client->lock);
826                 return NULL;
827
828                 /* LCOV_EXCL_STOP */
829         }
830
831         LIST_INITHEAD(&private_output->vblank_list);
832         LIST_INITHEAD(&private_output->change_handler_list);
833
834         wl_tdm_output_add_listener(private_output->output,
835                                                            &tdm_client_output_listener, private_output);
836         wl_display_roundtrip_queue(private_client->display, private_client->queue);
837
838         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
839
840         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
841                 wl_tdm_output_destroy(private_output->output);
842                 free(private_output);
843                 if (error)
844                         *error = TDM_ERROR_PROTOCOL_ERROR;
845                 pthread_mutex_unlock(&private_client->lock);
846                 return NULL;
847         }
848
849         LIST_ADDTAIL(&private_output->link, &private_client->output_list);
850
851         pthread_mutex_unlock(&private_client->lock);
852
853         return (tdm_client_output*)private_output;
854 }
855
856 tdm_error
857 tdm_client_output_add_change_handler(tdm_client_output *output,
858                                                                          tdm_client_output_change_handler func,
859                                                                          void *user_data)
860 {
861         tdm_private_client_output *private_output;
862         tdm_private_client *private_client;
863         tdm_client_output_handler_info *h = NULL;
864
865         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
866         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
867
868         private_output = (tdm_private_client_output*)output;
869         private_client = private_output->private_client;
870
871         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
872                 if (h->func == func && h->user_data == user_data) {
873                         TDM_ERR("can't add twice");
874                         return TDM_ERROR_BAD_REQUEST;
875                 }
876         }
877
878         h = calloc(1, sizeof *h);
879         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
880
881         pthread_mutex_lock(&private_client->lock);
882
883         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
884                 free(h);
885                 pthread_mutex_unlock(&private_client->lock);
886                 return TDM_ERROR_PROTOCOL_ERROR;
887         }
888
889         if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
890                 wl_tdm_output_watch_output_changes(private_output->output, 1);
891                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
892
893                 /* TODO: this is very tricky.
894                  * If a client adds the change_handler, we might be able to guess that
895                  * the client will watch the tdm client's fd and handle tdm events in
896                  * event loop. Otherwise, we CAN'T make sure if a client has event loop
897                  * which handles tdm events.
898                  */
899                 private_output->watch_output_changes = 1;
900         }
901
902         h->private_output = private_output;
903         h->func = func;
904         h->user_data = user_data;
905         LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
906         LIST_INITHEAD(&h->call_link);
907
908         pthread_mutex_unlock(&private_client->lock);
909
910         return TDM_ERROR_NONE;
911 }
912
913 void
914 tdm_client_output_remove_change_handler(tdm_client_output *output,
915                                                                                 tdm_client_output_change_handler func,
916                                                                                 void *user_data)
917 {
918         tdm_private_client_output *private_output;
919         tdm_private_client *private_client;
920         tdm_client_output_handler_info *h = NULL;
921
922         TDM_RETURN_IF_FAIL(output != NULL);
923         TDM_RETURN_IF_FAIL(func != NULL);
924
925         private_output = (tdm_private_client_output*)output;
926         private_client = private_output->private_client;
927
928         pthread_mutex_lock(&private_client->lock);
929
930         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
931                 if (h->func != func || h->user_data != user_data)
932                         continue;
933
934                 LIST_DEL(&h->link);
935                 free(h);
936
937                 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
938                         private_output->watch_output_changes = 0;
939                         if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
940                                 wl_tdm_output_watch_output_changes(private_output->output, 0);
941                                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
942                         }
943                 }
944
945                 pthread_mutex_unlock(&private_client->lock);
946
947                 return;
948         }
949
950         pthread_mutex_unlock(&private_client->lock);
951 }
952
953 tdm_error
954 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
955 {
956         tdm_private_client_output *private_output;
957         tdm_private_client *private_client;
958
959         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
960         TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
961
962         private_output = (tdm_private_client_output*)output;
963         private_client = private_output->private_client;
964
965         pthread_mutex_lock(&private_client->lock);
966
967         if (private_output->watch_output_changes) {
968                 *refresh = private_output->refresh;
969                 pthread_mutex_unlock(&private_client->lock);
970                 return TDM_ERROR_NONE;
971         }
972
973         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
974                 pthread_mutex_unlock(&private_client->lock);
975                 return TDM_ERROR_PROTOCOL_ERROR;
976         }
977
978         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
979         wl_tdm_output_get_mode(private_output->output);
980         wl_display_roundtrip_queue(private_client->display, private_client->queue);
981         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
982
983         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
984                 pthread_mutex_unlock(&private_client->lock);
985                 return TDM_ERROR_PROTOCOL_ERROR;
986         }
987
988         *refresh = private_output->refresh;
989
990         pthread_mutex_unlock(&private_client->lock);
991
992         return TDM_ERROR_NONE;
993 }
994
995 tdm_error
996 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
997 {
998         tdm_private_client_output *private_output;
999         tdm_private_client *private_client;
1000
1001         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1002         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1003
1004         private_output = (tdm_private_client_output*)output;
1005         private_client = private_output->private_client;
1006
1007         pthread_mutex_lock(&private_client->lock);
1008
1009         if (private_output->watch_output_changes) {
1010                 *status = private_output->connection;
1011                 pthread_mutex_unlock(&private_client->lock);
1012                 return TDM_ERROR_NONE;
1013         }
1014
1015         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1016                 pthread_mutex_unlock(&private_client->lock);
1017                 return TDM_ERROR_PROTOCOL_ERROR;
1018         }
1019
1020         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1021         wl_tdm_output_get_connection(private_output->output);
1022         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1023         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1024
1025         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1026                 pthread_mutex_unlock(&private_client->lock);
1027                 return TDM_ERROR_PROTOCOL_ERROR;
1028         }
1029
1030         *status = private_output->connection;
1031
1032         pthread_mutex_unlock(&private_client->lock);
1033
1034         return TDM_ERROR_NONE;
1035 }
1036
1037 tdm_error
1038 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1039 {
1040         tdm_private_client_output *private_output;
1041         tdm_private_client *private_client;
1042
1043         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1044         TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1045
1046         private_output = (tdm_private_client_output*)output;
1047         private_client = private_output->private_client;
1048
1049         if (private_output->watch_output_changes) {
1050                 *dpms = private_output->dpms;
1051                 return TDM_ERROR_NONE;
1052         }
1053
1054         pthread_mutex_lock(&private_client->lock);
1055
1056         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1057                 pthread_mutex_unlock(&private_client->lock);
1058                 return TDM_ERROR_PROTOCOL_ERROR;
1059         }
1060
1061         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1062         wl_tdm_output_get_dpms(private_output->output);
1063         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1064         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1065
1066         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1067                 pthread_mutex_unlock(&private_client->lock);
1068                 return TDM_ERROR_PROTOCOL_ERROR;
1069         }
1070
1071         *dpms = private_output->dpms;
1072
1073         pthread_mutex_unlock(&private_client->lock);
1074
1075         return TDM_ERROR_NONE;
1076 }
1077
1078 tdm_client_vblank*
1079 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1080 {
1081         tdm_private_client *private_client;
1082         tdm_private_client_output *private_output;
1083         tdm_private_client_vblank *private_vblank;
1084         struct wl_proxy *wrapper;
1085
1086         if (error)
1087                 *error = TDM_ERROR_NONE;
1088
1089         if (!output) {
1090                 TDM_ERR("'!output' failed");
1091                 if (error)
1092                         *error = TDM_ERROR_INVALID_PARAMETER;
1093                 return NULL;
1094         }
1095
1096         private_output = (tdm_private_client_output*)output;
1097         private_client = private_output->private_client;
1098
1099         pthread_mutex_lock(&private_client->lock);
1100
1101         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1102                 if (error)
1103                         *error = TDM_ERROR_PROTOCOL_ERROR;
1104                 pthread_mutex_unlock(&private_client->lock);
1105                 return NULL;
1106         }
1107
1108         wrapper = wl_proxy_create_wrapper(private_output->output);
1109         if (!wrapper) {
1110                 TDM_ERR("create output_wrapper failed");
1111                 if (error)
1112                         *error = TDM_ERROR_OUT_OF_MEMORY;
1113                 pthread_mutex_unlock(&private_client->lock);
1114                 return NULL;
1115         }
1116
1117         wl_proxy_set_queue(wrapper, private_client->queue);
1118
1119         private_vblank = calloc(1, sizeof *private_vblank);
1120         if (!private_vblank) {
1121                 /* LCOV_EXCL_START */
1122
1123                 TDM_ERR("alloc failed");
1124                 wl_proxy_wrapper_destroy(wrapper);
1125                 if (error)
1126                         *error = TDM_ERROR_OUT_OF_MEMORY;
1127                 pthread_mutex_unlock(&private_client->lock);
1128                 return NULL;
1129
1130                 /* LCOV_EXCL_STOP */
1131         }
1132
1133         private_vblank->private_output = private_output;
1134
1135         private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1136         wl_proxy_wrapper_destroy(wrapper);
1137         if (!private_vblank->vblank) {
1138                 /* LCOV_EXCL_START */
1139
1140                 TDM_ERR("couldn't create vblank resource");
1141                 free(private_vblank);
1142                 if (error)
1143                         *error = TDM_ERROR_OUT_OF_MEMORY;
1144                 pthread_mutex_unlock(&private_client->lock);
1145                 return NULL;
1146
1147                 /* LCOV_EXCL_STOP */
1148         }
1149
1150         /* initial value */
1151         private_vblank->fps = private_output->refresh;
1152         private_vblank->offset = 0;
1153         private_vblank->enable_fake = 0;
1154
1155         LIST_INITHEAD(&private_vblank->wait_list);
1156
1157         wl_tdm_vblank_add_listener(private_vblank->vblank,
1158                                                            &tdm_client_vblank_listener, private_vblank);
1159         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1160
1161         wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1162
1163         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1164                 wl_tdm_vblank_destroy(private_vblank->vblank);
1165                 free(private_vblank);
1166                 if (error)
1167                         *error = TDM_ERROR_PROTOCOL_ERROR;
1168                 pthread_mutex_unlock(&private_client->lock);
1169                 return NULL;
1170         }
1171
1172         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1173
1174         pthread_mutex_unlock(&private_client->lock);
1175
1176         return (tdm_client_vblank*)private_vblank;
1177 }
1178
1179 void
1180 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1181 {
1182         tdm_private_client_vblank *private_vblank;
1183         tdm_private_client *private_client;
1184         tdm_client_wait_info *w = NULL, *ww = NULL;
1185
1186         TDM_RETURN_IF_FAIL(vblank != NULL);
1187
1188         private_vblank = vblank;
1189         private_client = private_vblank->private_output->private_client;
1190
1191         pthread_mutex_lock(&private_client->lock);
1192
1193         LIST_DEL(&private_vblank->link);
1194
1195         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1196                 LIST_DEL(&w->link);
1197                 free(w);
1198         }
1199
1200         wl_tdm_vblank_destroy(private_vblank->vblank);
1201
1202         free(private_vblank);
1203
1204         pthread_mutex_unlock(&private_client->lock);
1205 }
1206
1207 tdm_error
1208 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1209 {
1210         tdm_private_client_vblank *private_vblank;
1211         tdm_private_client *private_client;
1212
1213         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1214
1215         private_vblank = vblank;
1216         private_client = private_vblank->private_output->private_client;
1217
1218         pthread_mutex_lock(&private_client->lock);
1219
1220         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1221                 pthread_mutex_unlock(&private_client->lock);
1222                 return TDM_ERROR_PROTOCOL_ERROR;
1223         }
1224
1225         if (!name)
1226                 name = TDM_VBLANK_DEFAULT_NAME;
1227
1228         strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1229         private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1230
1231         wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1232
1233         pthread_mutex_unlock(&private_client->lock);
1234
1235         return TDM_ERROR_NONE;
1236 }
1237
1238 tdm_error
1239 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1240 {
1241         tdm_private_client_vblank *private_vblank;
1242         tdm_private_client *private_client;
1243
1244         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1245
1246         private_vblank = vblank;
1247         private_client = private_vblank->private_output->private_client;
1248
1249         pthread_mutex_lock(&private_client->lock);
1250         private_vblank->sync = sync;
1251         pthread_mutex_unlock(&private_client->lock);
1252
1253         return TDM_ERROR_NONE;
1254 }
1255
1256 tdm_error
1257 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1258 {
1259         tdm_private_client_vblank *private_vblank;
1260         tdm_private_client *private_client;
1261
1262         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1263         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1264
1265         private_vblank = vblank;
1266         private_client = private_vblank->private_output->private_client;
1267
1268         pthread_mutex_lock(&private_client->lock);
1269
1270         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1271                 pthread_mutex_unlock(&private_client->lock);
1272                 return TDM_ERROR_PROTOCOL_ERROR;
1273         }
1274
1275         if (private_vblank->fps == fps) {
1276                 pthread_mutex_unlock(&private_client->lock);
1277                 return TDM_ERROR_NONE;
1278         }
1279
1280         private_vblank->fps = fps;
1281
1282         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1283
1284         pthread_mutex_unlock(&private_client->lock);
1285
1286         return TDM_ERROR_NONE;
1287 }
1288
1289 tdm_error
1290 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1291 {
1292         tdm_private_client_vblank *private_vblank;
1293         tdm_private_client *private_client;
1294
1295         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1296
1297         private_vblank = vblank;
1298         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1299
1300         private_client = private_vblank->private_output->private_client;
1301
1302         pthread_mutex_lock(&private_client->lock);
1303
1304         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1305                 pthread_mutex_unlock(&private_client->lock);
1306                 return TDM_ERROR_PROTOCOL_ERROR;
1307         }
1308
1309         if (private_vblank->offset == offset_ms) {
1310                 pthread_mutex_unlock(&private_client->lock);
1311                 return TDM_ERROR_NONE;
1312         }
1313
1314         private_vblank->offset = offset_ms;
1315
1316         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1317
1318         pthread_mutex_unlock(&private_client->lock);
1319
1320         return TDM_ERROR_NONE;
1321 }
1322
1323 tdm_error
1324 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1325 {
1326         tdm_private_client_vblank *private_vblank;
1327         tdm_private_client *private_client;
1328
1329         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1330
1331         private_vblank = vblank;
1332         private_client = private_vblank->private_output->private_client;
1333
1334         pthread_mutex_lock(&private_client->lock);
1335
1336         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1337                 pthread_mutex_unlock(&private_client->lock);
1338                 return TDM_ERROR_PROTOCOL_ERROR;
1339         }
1340
1341         if (private_vblank->enable_fake == enable_fake) {
1342                 pthread_mutex_unlock(&private_client->lock);
1343                 return TDM_ERROR_NONE;
1344         }
1345
1346         private_vblank->enable_fake = enable_fake;
1347
1348         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1349
1350         pthread_mutex_unlock(&private_client->lock);
1351
1352         return TDM_ERROR_NONE;
1353 }
1354
1355 tdm_error
1356 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1357 {
1358         tdm_private_client *private_client;
1359         tdm_private_client_output *private_output;
1360         tdm_private_client_vblank *private_vblank;
1361         tdm_client_wait_info *w;
1362         struct timespec tp;
1363         unsigned int req_sec, req_usec;
1364         int ret = 0;
1365
1366         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1367         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1368         /* can't support "interval 0" and "getting current_msc" things because
1369          * there is a socket communication between TDM client and server. It's impossible
1370          * to return the current msc or sequence immediately.
1371          */
1372         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1373
1374         private_vblank = vblank;
1375         private_output = private_vblank->private_output;
1376         private_client = private_output->private_client;
1377
1378         pthread_mutex_lock(&private_client->lock);
1379
1380         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1381                 pthread_mutex_unlock(&private_client->lock);
1382                 return TDM_ERROR_PROTOCOL_ERROR;
1383         }
1384
1385         if (!private_vblank->started)
1386                 private_vblank->started = 1;
1387
1388         if (!private_vblank->enable_fake) {
1389                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1390                         TDM_ERR("output disconnected");
1391                         pthread_mutex_unlock(&private_client->lock);
1392                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1393                 }
1394                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1395                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1396                         pthread_mutex_unlock(&private_client->lock);
1397                         return TDM_ERROR_DPMS_OFF;
1398                 }
1399         }
1400
1401         w = calloc(1, sizeof *w);
1402         if (!w) {
1403                 /* LCOV_EXCL_START */
1404
1405                 TDM_ERR("alloc failed");
1406                 pthread_mutex_unlock(&private_client->lock);
1407                 return TDM_ERROR_OUT_OF_MEMORY;
1408
1409                 /* LCOV_EXCL_STOP */
1410         }
1411
1412         w->private_vblank = private_vblank;
1413         w->func = func;
1414         w->user_data = user_data;
1415
1416         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1417         LIST_INITHEAD(&w->call_link);
1418
1419         clock_gettime(CLOCK_MONOTONIC, &tp);
1420         req_sec = (unsigned int)tp.tv_sec;
1421         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1422
1423         w->req_id = ++private_output->req_id;
1424         w->req_time = TDM_TIME(req_sec, req_usec);
1425         w->need_free = (private_vblank->sync) ? 0 : 1;
1426
1427         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1428
1429         if (private_vblank->enable_ttrace)
1430                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1431
1432         TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1433                         vblank, interval, w->req_id, w->req_time);
1434
1435         private_vblank->req_time = w->req_time;
1436
1437         if (private_vblank->last_time >= w->req_time)
1438                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1439
1440         if (!private_vblank->sync) {
1441                 wl_display_flush(private_client->display);
1442                 pthread_mutex_unlock(&private_client->lock);
1443                 return TDM_ERROR_NONE;
1444         }
1445
1446         /* LCOV_EXCL_START */
1447
1448         while (ret != -1 && !w->need_free)
1449                 ret = wl_display_dispatch(private_client->display);
1450
1451         clock_gettime(CLOCK_MONOTONIC, &tp);
1452         TDM_DBG("block during %d us",
1453                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1454                         - (req_sec * 1000000 + req_usec));
1455
1456         LIST_DEL(&w->link);
1457         free(w);
1458
1459         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1460                 pthread_mutex_unlock(&private_client->lock);
1461                 return TDM_ERROR_PROTOCOL_ERROR;
1462         }
1463
1464         pthread_mutex_unlock(&private_client->lock);
1465
1466         return TDM_ERROR_NONE;
1467
1468         /* LCOV_EXCL_STOP */
1469 }
1470
1471 tdm_error
1472 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1473                                                    tdm_client_vblank_handler func, void *user_data)
1474 {
1475         tdm_private_client *private_client;
1476         tdm_private_client_output *private_output;
1477         tdm_private_client_vblank *private_vblank;
1478         tdm_client_wait_info *w;
1479         struct timespec tp;
1480         unsigned int req_sec, req_usec;
1481         int ret = 0;
1482
1483         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1484         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1485
1486         private_vblank = vblank;
1487         private_output = private_vblank->private_output;
1488         private_client = private_output->private_client;
1489
1490         pthread_mutex_lock(&private_client->lock);
1491
1492         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1493                 pthread_mutex_unlock(&private_client->lock);
1494                 return TDM_ERROR_PROTOCOL_ERROR;
1495         }
1496
1497         if (!private_vblank->started)
1498                 private_vblank->started = 1;
1499
1500         if (!private_vblank->enable_fake) {
1501                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1502                         TDM_ERR("output disconnected");
1503                         pthread_mutex_unlock(&private_client->lock);
1504                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1505                 }
1506                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1507                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1508                         pthread_mutex_unlock(&private_client->lock);
1509                         return TDM_ERROR_DPMS_OFF;
1510                 }
1511         }
1512
1513         w = calloc(1, sizeof *w);
1514         if (!w) {
1515                 /* LCOV_EXCL_START */
1516
1517                 TDM_ERR("alloc failed");
1518                 pthread_mutex_unlock(&private_client->lock);
1519                 return TDM_ERROR_OUT_OF_MEMORY;
1520
1521                 /* LCOV_EXCL_STOP */
1522         }
1523
1524         w->private_vblank = private_vblank;
1525         w->func = func;
1526         w->user_data = user_data;
1527
1528         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1529         LIST_INITHEAD(&w->call_link);
1530
1531         clock_gettime(CLOCK_MONOTONIC, &tp);
1532         req_sec = (unsigned int)tp.tv_sec;
1533         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1534
1535         w->req_id = ++private_output->req_id;
1536         w->req_time = TDM_TIME(req_sec, req_usec);
1537         w->need_free = (private_vblank->sync) ? 0 : 1;
1538
1539         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1540
1541         if (private_vblank->enable_ttrace)
1542                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1543
1544         TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1545                         vblank, sequence, w->req_id, w->req_time);
1546
1547         private_vblank->req_time = w->req_time;
1548
1549         if (private_vblank->last_time >= w->req_time)
1550                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1551
1552         if (!private_vblank->sync) {
1553                 wl_display_flush(private_client->display);
1554                 pthread_mutex_unlock(&private_client->lock);
1555                 return TDM_ERROR_NONE;
1556         }
1557
1558         /* LCOV_EXCL_START */
1559
1560         while (ret != -1 && !w->need_free)
1561                 ret = wl_display_dispatch(private_client->display);
1562
1563         clock_gettime(CLOCK_MONOTONIC, &tp);
1564         TDM_DBG("block during %d us",
1565                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1566                         - (req_sec * 1000000 + req_usec));
1567
1568         LIST_DEL(&w->link);
1569         free(w);
1570
1571         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1572                 pthread_mutex_unlock(&private_client->lock);
1573                 return TDM_ERROR_PROTOCOL_ERROR;
1574         }
1575
1576         pthread_mutex_unlock(&private_client->lock);
1577
1578         return TDM_ERROR_NONE;
1579
1580         /* LCOV_EXCL_STOP */
1581 }
1582
1583 unsigned int
1584 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1585 {
1586         tdm_private_client_vblank *private_vblank;
1587
1588         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1589
1590         private_vblank = vblank;
1591
1592         return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1593 }