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