virtual: add protocol to share wl_buffer(tbm_surface) with tdm_client
[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 #define WL_HIDE_DEPRECATED
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <time.h>
46 #include <strings.h>
47 #include <poll.h>
48
49 #include <tdm-client-protocol.h>
50
51 #include "tdm_client.h"
52 #include "tdm_log.h"
53 #include "tdm_macro.h"
54 #include "tdm_list.h"
55 #include "tdm.h"
56 #include "tdm_private.h"
57
58 #define TDM_ARRAY_NTH_DATA(array, type, n) (((type*)((array)->data)) + n)
59
60 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
61
62 typedef struct _tdm_private_client {
63         pthread_mutex_t lock;
64
65         struct wl_display *display;
66         struct wl_event_queue *queue;
67         struct wl_registry *registry;
68         struct wl_tdm *tdm;
69         struct list_head output_list;
70
71         unsigned int enable_ttrace;
72         unsigned int stamp;
73
74         tdm_private_client_vblank *temp_vblank;
75 } tdm_private_client;
76
77 typedef struct _tdm_private_client_output {
78         tdm_private_client *private_client;
79
80         char name[TDM_NAME_LEN];
81         struct wl_tdm_output *output;
82         int width;
83         int height;
84         int refresh;
85         tdm_output_conn_status connection;
86         tdm_output_dpms dpms;
87         struct list_head vblank_list;
88         struct list_head change_handler_list;
89
90         unsigned int req_id;
91         unsigned int watch_output_changes;
92
93         struct list_head link;
94 } tdm_private_client_output;
95
96 typedef struct _tdm_private_client_buffer {
97         struct list_head link;
98         struct wl_buffer *wl_buffer;
99 } tdm_private_client_buffer;
100
101 typedef struct _tdm_private_client_voutput {
102     tdm_private_client_output base;
103         struct wl_tdm_voutput *wl_voutput;
104         struct list_head commit_handler_list;
105
106         struct
107         {
108                 int count;
109                 tdm_client_output_mode *modes;
110         } available_modes;
111
112         unsigned int mmwidth;
113         unsigned int mmheight;
114
115         uint32_t msg;
116
117         struct list_head buffer_list;
118         tbm_bufmgr bufmgr;
119         tdm_private_client_buffer *commit_buffer;
120 } tdm_private_client_voutput;
121
122 struct _tdm_private_client_vblank {
123         tdm_private_client_output *private_output;
124
125         struct wl_tdm_vblank *vblank;
126         struct list_head wait_list;
127
128         char name[TDM_NAME_LEN];
129         unsigned int sync;
130         unsigned int fps;
131         int offset;
132         unsigned int enable_fake;
133         unsigned int enable_ttrace;
134
135         unsigned int started;
136         unsigned int stamp;
137
138         double req_time;
139         double last_time;
140
141         struct list_head link;
142 };
143
144 typedef struct _tdm_client_output_handler_info {
145         tdm_private_client_output *private_output;
146
147         tdm_client_output_change_handler func;
148         void *user_data;
149
150         struct list_head link;
151         struct list_head call_link;
152 } tdm_client_output_handler_info;
153
154 typedef struct _tdm_client_wait_info {
155         tdm_private_client_vblank *private_vblank;
156
157         tdm_client_vblank_handler func;
158         void *user_data;
159
160         unsigned int req_id;
161         double req_time;
162         int need_free;
163
164         struct list_head link;
165         struct list_head call_link;
166 } tdm_client_wait_info;
167
168 typedef struct _tdm_client_voutput_commit_handler_info
169 {
170         tdm_private_client_voutput *private_voutput;
171
172         tdm_client_voutput_commit_handler func;
173         void *user_data;
174
175         struct list_head link;
176         struct list_head call_link;
177 } tdm_client_voutput_commit_handler_info;
178
179 static unsigned int
180 _tdm_client_check_wl_error(tdm_private_client *private_client, const char *func, int line)
181 {
182         uint32_t ec, id;
183         const struct wl_interface *intf;
184         int err;
185
186         err = wl_display_get_error(private_client->display);
187         if (!err)
188                 return false;
189
190         if (err == EINVAL || err == ENOMEM || err == EFAULT || err == EPROTO) {
191                 ec = wl_display_get_protocol_error(private_client->display, &intf, &id);
192                 TDM_ERR("[%s,%d] errno(%d) Got protocol error '%u' on interface '%s' (object '%u')",
193                                 func, line, err, ec, (intf) ? intf->name : "destroyed", id);
194         } else {
195                 TDM_ERR("[%s,%d] errno(%d)", func, line, err);
196         }
197
198         return true;
199 }
200
201 #define CHECK_WL_PROTOCOL_ERROR(pc)  _tdm_client_check_wl_error(pc, __FUNCTION__, __LINE__)
202
203 static void
204 _tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
205 {
206         tdm_private_client_vblank *private_vblank = data;
207         tdm_private_client *private_client;
208
209         TDM_RETURN_IF_FAIL(private_vblank != NULL);
210
211         private_vblank->stamp = stamp;
212
213         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
214         private_client = private_vblank->private_output->private_client;
215
216         private_client->stamp = stamp;
217 }
218
219 /* LCOV_EXCL_START */
220 static void
221 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
222                                                    uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
223                                                    uint32_t tv_usec, uint32_t error)
224 {
225         tdm_private_client_vblank *private_vblank = data;
226         tdm_private_client *private_client;
227         tdm_client_wait_info *w = NULL, *wait_info = NULL;
228
229         TDM_RETURN_IF_FAIL(private_vblank != NULL);
230
231         private_client = private_vblank->private_output->private_client;
232
233         private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
234
235         TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
236                         private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
237
238         LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
239                 if (w->req_id != req_id)
240                         continue;
241
242                 wait_info = w;
243                 break;
244         }
245
246         if (!wait_info) {
247                 TDM_ERR("no wait infomation for req_id(%d)", req_id);
248                 return;
249         }
250
251         if (private_vblank->enable_ttrace)
252                 TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
253
254         if (wait_info->req_time >= private_vblank->last_time)
255                 TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
256
257         if (wait_info->need_free)
258                 LIST_DEL(&wait_info->link);
259
260         if (wait_info->func) {
261                 pthread_mutex_unlock(&private_client->lock);
262                 wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
263                 pthread_mutex_lock(&private_client->lock);
264         }
265
266         if (wait_info->need_free)
267                 free(w);
268         else
269                 wait_info->need_free = 1;
270 }
271 /* LCOV_EXCL_STOP */
272
273 /* LCOV_EXCL_START */
274 static void
275 _tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable)
276 {
277         tdm_private_client_vblank *private_vblank = data;
278         tdm_private_client *private_client;
279
280         TDM_RETURN_IF_FAIL(private_vblank != NULL);
281
282         private_vblank->enable_ttrace = enable;
283
284         TDM_RETURN_IF_FAIL(private_vblank->private_output != NULL);
285         private_client = private_vblank->private_output->private_client;
286
287         private_client->enable_ttrace = enable;
288 }
289 /* LCOV_EXCL_STOP */
290
291 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
292         _tdm_client_vblank_cb_stamp,
293         _tdm_client_vblank_cb_done,
294         _tdm_client_vblank_cb_ttrace,
295 };
296
297 static void
298 _tdm_client_output_destroy(tdm_private_client_output *private_output)
299 {
300         tdm_private_client_vblank *v = NULL, *vv = NULL;
301         tdm_client_output_handler_info *h = NULL, *hh = NULL;
302
303         LIST_DEL(&private_output->link);
304
305         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_list, link) {
306                 TDM_ERR("vblanks SHOULD be destroyed first!");
307                 LIST_DEL(&v->link);
308                 v->private_output = NULL;
309         }
310
311         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) {
312                 LIST_DEL(&h->link);
313                 free(h);
314         }
315
316         wl_tdm_output_destroy(private_output->output);
317
318         free(private_output);
319 }
320
321 static void
322 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
323                                                    uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
324 {
325         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
326
327         TDM_RETURN_IF_FAIL(private_output != NULL);
328
329         private_output->width = width;
330         private_output->height = height;
331         private_output->refresh = refresh;
332
333         if (error != TDM_ERROR_NONE)
334                 TDM_INFO("mode event error: %d", error);
335
336         TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
337                         private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
338                         width, height, refresh);
339 }
340
341 static void
342 _tdm_client_output_cb_connection(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 (private_output->connection == value)
355                 return;
356
357         private_output->connection = value;
358
359         if (error != TDM_ERROR_NONE)
360                 TDM_INFO("connection event error: %d", error);
361
362         TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
363                         private_output,
364                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
365                         value);
366
367         LIST_INITHEAD(&call_list);
368
369         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
370                 LIST_ADDTAIL(&h->call_link, &call_list);
371         }
372
373         v.u32 = value;
374         pthread_mutex_unlock(&private_client->lock);
375         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
376                 if (h->func)
377                         h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
378         }
379         pthread_mutex_lock(&private_client->lock);
380 }
381
382 static void
383 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
384 {
385         tdm_private_client_output *private_output = (tdm_private_client_output*)data;
386         tdm_private_client *private_client;
387         tdm_client_output_handler_info *h = NULL, *hh = NULL;
388         tdm_value v;
389         struct list_head call_list;
390
391         TDM_RETURN_IF_FAIL(private_output != NULL);
392
393         private_client = private_output->private_client;
394
395         /* If value is extended value, we handle it as DPMS on in client side
396          * The extended DPMS value is valid only in server side.
397          * Or, need to export to client side also?
398          */
399         if (value > TDM_OUTPUT_DPMS_OFF)
400                 value = TDM_OUTPUT_DPMS_ON;
401
402         if (private_output->dpms == value)
403                 return;
404
405         private_output->dpms = value;
406
407         if (error != TDM_ERROR_NONE)
408                 TDM_INFO("dpms event error: %d", error);
409
410         TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
411                         private_output,
412                         wl_proxy_get_id((struct wl_proxy*)private_output->output),
413                         value);
414
415         LIST_INITHEAD(&call_list);
416
417         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
418                 LIST_ADDTAIL(&h->call_link, &call_list);
419         }
420
421         v.u32 = value;
422         pthread_mutex_unlock(&private_client->lock);
423         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
424                 if (h->func)
425                         h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
426         }
427         pthread_mutex_lock(&private_client->lock);
428 }
429
430 static const struct wl_tdm_output_listener tdm_client_output_listener = {
431         _tdm_client_output_cb_mode,
432         _tdm_client_output_cb_connection,
433         _tdm_client_output_cb_dpms,
434 };
435
436 static void
437 _tdm_client_cb_global(void *data, struct wl_registry *registry,
438                                           uint32_t name, const char *interface,
439                                           uint32_t version)
440 {
441         tdm_private_client *private_client = data;
442
443         if (strncmp(interface, "wl_tdm", 6) == 0) {
444                 private_client->tdm =
445                         wl_registry_bind(registry, name, &wl_tdm_interface, version);
446                 TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
447
448                 wl_display_flush(private_client->display);
449         }
450 }
451
452 /* LCOV_EXCL_START */
453 static void
454 _tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
455 {
456 }
457 /* LCOV_EXCL_STOP */
458
459 static const struct wl_registry_listener tdm_client_registry_listener = {
460         _tdm_client_cb_global,
461         _tdm_client_cb_global_remove
462 };
463
464 tdm_client*
465 tdm_client_create(tdm_error *error)
466 {
467         tdm_private_client *private_client;
468
469         private_client = calloc(1, sizeof *private_client);
470         if (!private_client) {
471                 /* LCOV_EXCL_START */
472
473                 TDM_ERR("alloc failed");
474                 if (error)
475                         *error = TDM_ERROR_OUT_OF_MEMORY;
476                 return NULL;
477
478                 /* LCOV_EXCL_STOP */
479         }
480
481         if (pthread_mutex_init(&private_client->lock, NULL)) {
482                 TDM_ERR("mutex init failed: %m");
483                 free(private_client);
484                 if (error)
485                         *error = TDM_ERROR_OUT_OF_MEMORY;
486                 return NULL;
487         }
488
489         LIST_INITHEAD(&private_client->output_list);
490
491         private_client->display = wl_display_connect("tdm-socket");
492         TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed);
493
494         private_client->queue = wl_display_create_queue(private_client->display);
495         TDM_GOTO_IF_FAIL(private_client->queue != NULL, create_failed);
496
497         private_client->registry = wl_display_get_registry(private_client->display);
498         TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed);
499
500         wl_registry_add_listener(private_client->registry,
501                                                          &tdm_client_registry_listener, private_client);
502         wl_display_roundtrip(private_client->display);
503
504         if (CHECK_WL_PROTOCOL_ERROR(private_client))
505                 goto create_failed;
506
507         /* check global objects */
508         TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed);
509
510         if (error)
511                 *error = TDM_ERROR_NONE;
512
513         return (tdm_client*)private_client;
514 create_failed:
515         tdm_client_destroy((tdm_client*)private_client);
516         if (error)
517                 *error = TDM_ERROR_OPERATION_FAILED;
518         return NULL;
519 }
520
521 void
522 tdm_client_destroy(tdm_client *client)
523 {
524         tdm_private_client *private_client = (tdm_private_client*)client;
525         tdm_private_client_output *o = NULL, *oo = NULL;
526
527         if (!private_client)
528                 return;
529
530         pthread_mutex_lock(&private_client->lock);
531
532         if (private_client->temp_vblank) {
533                 pthread_mutex_unlock(&private_client->lock);
534                 tdm_client_vblank_destroy(private_client->temp_vblank);
535                 pthread_mutex_lock(&private_client->lock);
536         }
537
538         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_client->output_list, link) {
539                 _tdm_client_output_destroy(o);
540         }
541
542         if (private_client->tdm)
543                 wl_tdm_destroy(private_client->tdm);
544         if (private_client->registry)
545                 wl_registry_destroy(private_client->registry);
546         if (private_client->queue)
547                 wl_event_queue_destroy(private_client->queue);
548         if (private_client->display)
549                 wl_display_disconnect(private_client->display);
550
551         pthread_mutex_unlock(&private_client->lock);
552         pthread_mutex_destroy(&private_client->lock);
553
554         free(private_client);
555 }
556
557 tdm_error
558 tdm_client_get_fd(tdm_client *client, int *fd)
559 {
560         tdm_private_client *private_client;
561
562         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
563         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
564
565         private_client = (tdm_private_client*)client;
566
567         pthread_mutex_lock(&private_client->lock);
568
569         *fd = wl_display_get_fd(private_client->display);
570
571         pthread_mutex_unlock(&private_client->lock);
572
573         if (*fd < 0)
574                 return TDM_ERROR_OPERATION_FAILED;
575
576         return TDM_ERROR_NONE;
577 }
578
579 tdm_error
580 tdm_client_handle_events(tdm_client *client)
581 {
582         tdm_private_client *private_client;
583
584         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
585
586         /* LCOV_EXCL_START */
587         private_client = (tdm_private_client*)client;
588
589         pthread_mutex_lock(&private_client->lock);
590
591         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
592                 pthread_mutex_unlock(&private_client->lock);
593                 return TDM_ERROR_PROTOCOL_ERROR;
594         }
595
596         if (private_client->enable_ttrace)
597                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
598
599         wl_display_dispatch(private_client->display);
600
601         if (private_client->enable_ttrace)
602                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
603
604         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
605                 pthread_mutex_unlock(&private_client->lock);
606                 return TDM_ERROR_PROTOCOL_ERROR;
607         }
608
609         pthread_mutex_unlock(&private_client->lock);
610
611         return TDM_ERROR_NONE;
612         /* LCOV_EXCL_STOP */
613 }
614
615 static int
616 _tdm_client_poll(struct wl_display *display, short int events, int timeout)
617 {
618         int ret;
619         struct pollfd pfd[1];
620
621         pfd[0].fd = wl_display_get_fd(display);
622         pfd[0].events = events;
623         do {
624                 ret = poll(pfd, 1, timeout);
625         } while (ret == -1 && errno == EINTR);
626
627         return ret;
628 }
629
630 static tdm_error
631 _tdm_client_dispatch_timeout(tdm_private_client *private_client, int timeout)
632 {
633         int ret;
634         struct wl_display *display = private_client->display;
635
636         if (wl_display_prepare_read(display) == -1) {
637                 if (wl_display_dispatch_pending(display) > 0)
638                         return TDM_ERROR_NONE;
639                 else
640                         return TDM_ERROR_OPERATION_FAILED;
641         }
642
643         while (true) {
644                 ret = wl_display_flush(display);
645
646                 if (ret != -1 || errno != EAGAIN)
647                         break;
648
649                 if (_tdm_client_poll(display, POLLOUT, -1) == -1) {
650                         wl_display_cancel_read(display);
651                         TDM_ERR("_tdm_client_poll failed");
652                         return TDM_ERROR_OPERATION_FAILED;
653                 }
654         }
655
656         /* Don't stop if flushing hits an EPIPE; continue so we can read any
657          * protocol error that may have triggered it. */
658         if (ret < 0 && errno != EPIPE) {
659                 TDM_ERR("ret(%d) errno(%d)", ret, errno);
660                 wl_display_cancel_read(display);
661                 return TDM_ERROR_OPERATION_FAILED;
662         }
663
664         ret = _tdm_client_poll(display, POLLIN, timeout);
665         if (ret <= 0) {
666                 wl_display_cancel_read(display);
667                 if (ret == 0) {
668                         TDM_ERR("_tdm_client_poll timeout.");
669                         return TDM_ERROR_TIMEOUT;
670                 } else {
671                         TDM_ERR("_tdm_client_poll failed. (ret:%d)", ret);
672                         return TDM_ERROR_OPERATION_FAILED;
673                 }
674         }
675
676         if (wl_display_read_events(display) == -1) {
677                 TDM_ERR("wl_display_read_events failed");
678                 return TDM_ERROR_OPERATION_FAILED;
679         }
680
681         ret = wl_display_dispatch_pending(display);
682
683         if (ret < 0) {
684                 TDM_ERR("_tdm_client_dispatch_timeout failed");
685                 return TDM_ERROR_OPERATION_FAILED;
686         }
687
688         return TDM_ERROR_NONE;
689 }
690
691 tdm_error
692 tdm_client_handle_events_timeout(tdm_client *client, int ms_timeout)
693 {
694         tdm_private_client *private_client;
695         tdm_error ret;
696         TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_ERROR_INVALID_PARAMETER);
697
698         private_client = (tdm_private_client*)client;
699
700         pthread_mutex_lock(&private_client->lock);
701
702         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
703                 pthread_mutex_unlock(&private_client->lock);
704                 return TDM_ERROR_PROTOCOL_ERROR;
705         }
706
707         if (private_client->enable_ttrace)
708                 TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
709
710         ret = _tdm_client_dispatch_timeout(private_client, ms_timeout);
711
712         if (private_client->enable_ttrace)
713                 TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events_Timeout:%u", (unsigned int)private_client->stamp);
714
715         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
716                 pthread_mutex_unlock(&private_client->lock);
717                 return TDM_ERROR_PROTOCOL_ERROR;
718         }
719
720         pthread_mutex_unlock(&private_client->lock);
721
722         return ret;
723 }
724
725 typedef struct _tdm_client_vblank_temp {
726         tdm_client_vblank_handler2 func;
727         void *user_data;
728 } tdm_client_vblank_temp;
729
730 /* LCOV_EXCL_START */
731 static void
732 _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
733                                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
734 {
735         tdm_client_vblank_temp *vblank_temp = user_data;
736
737         TDM_RETURN_IF_FAIL(vblank_temp != NULL);
738         TDM_RETURN_IF_FAIL(vblank != NULL);
739
740         if (vblank_temp->func)
741                 vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
742
743         free(vblank_temp);
744 }
745 /* LCOV_EXCL_STOP */
746
747 /* LCOV_EXCL_START */ /* deprecated */
748 tdm_error
749 tdm_client_wait_vblank(tdm_client *client, char *name,
750                                            int sw_timer, int interval, int sync,
751                                            tdm_client_vblank_handler2 func, void *user_data)
752 {
753         tdm_private_client *private_client = (tdm_private_client*)client;
754         tdm_client_output *output;
755         tdm_client_vblank_temp *vblank_temp;
756         tdm_error ret;
757
758         TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
759         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
760         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
761
762         if (CHECK_WL_PROTOCOL_ERROR(private_client))
763                 return TDM_ERROR_PROTOCOL_ERROR;
764
765         if (!private_client->temp_vblank) {
766                 output = tdm_client_get_output(client, name, &ret);
767                 TDM_RETURN_VAL_IF_FAIL(output != NULL, ret);
768
769                 private_client->temp_vblank = tdm_client_output_create_vblank(output, &ret);
770                 TDM_RETURN_VAL_IF_FAIL(private_client->temp_vblank != NULL, ret);
771         }
772
773         tdm_client_vblank_set_enable_fake(private_client->temp_vblank, sw_timer);
774         tdm_client_vblank_set_sync(private_client->temp_vblank, sync);
775
776         vblank_temp = calloc(1, sizeof *vblank_temp);
777         TDM_RETURN_VAL_IF_FAIL(vblank_temp != NULL, TDM_ERROR_OUT_OF_MEMORY);
778
779         vblank_temp->func = func;
780         vblank_temp->user_data = user_data;
781
782         return tdm_client_vblank_wait(private_client->temp_vblank, interval, _tdm_client_vblank_handler_temp, vblank_temp);
783 }
784 /* LCOV_EXCL_STOP */
785
786 tdm_client_output*
787 tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
788 {
789         tdm_private_client *private_client;
790         tdm_private_client_output *private_output = NULL;
791         struct wl_proxy *wrapper;
792
793         if (error)
794                 *error = TDM_ERROR_NONE;
795
796         if (!client) {
797                 TDM_ERR("'!client' failed");
798                 if (error)
799                         *error = TDM_ERROR_INVALID_PARAMETER;
800                 return NULL;
801         }
802
803         private_client = (tdm_private_client*)client;
804
805         pthread_mutex_lock(&private_client->lock);
806
807         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
808                 if (error)
809                         *error = TDM_ERROR_PROTOCOL_ERROR;
810                 pthread_mutex_unlock(&private_client->lock);
811                 return NULL;
812         }
813
814         if (!name) {
815                 name = "primary";
816         } else if (strncmp(name, "primary", 7) && strncmp(name, "default", 7)) {
817                 if (error)
818                         *error = TDM_ERROR_INVALID_PARAMETER;
819                 pthread_mutex_unlock(&private_client->lock);
820                 return NULL;
821         }
822
823         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
824                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
825                         pthread_mutex_unlock(&private_client->lock);
826                         return (tdm_client_output*)private_output;
827                 }
828         }
829
830         wrapper = wl_proxy_create_wrapper(private_client->tdm);
831         if (!wrapper) {
832                 TDM_ERR("create output_wrapper failed");
833                 if (error)
834                         *error = TDM_ERROR_OUT_OF_MEMORY;
835                 pthread_mutex_unlock(&private_client->lock);
836                 return NULL;
837         }
838
839         wl_proxy_set_queue(wrapper, private_client->queue);
840
841         private_output = calloc(1, sizeof *private_output);
842         if (!private_output) {
843                 /* LCOV_EXCL_START */
844                 wl_proxy_wrapper_destroy(wrapper);
845                 TDM_ERR("alloc failed");
846                 if (error)
847                         *error = TDM_ERROR_OUT_OF_MEMORY;
848                 pthread_mutex_unlock(&private_client->lock);
849                 return NULL;
850
851                 /* LCOV_EXCL_STOP */
852         }
853
854         private_output->private_client = private_client;
855
856         snprintf(private_output->name, TDM_NAME_LEN, "%s", name);
857         private_output->output = wl_tdm_create_output((struct wl_tdm *)wrapper, private_output->name);
858         wl_proxy_wrapper_destroy(wrapper);
859         if (!private_output->output) {
860                 /* LCOV_EXCL_START */
861
862                 TDM_ERR("couldn't create output resource");
863                 free(private_output);
864                 if (error)
865                         *error = TDM_ERROR_OUT_OF_MEMORY;
866                 pthread_mutex_unlock(&private_client->lock);
867                 return NULL;
868
869                 /* LCOV_EXCL_STOP */
870         }
871
872         LIST_INITHEAD(&private_output->vblank_list);
873         LIST_INITHEAD(&private_output->change_handler_list);
874
875         wl_tdm_output_add_listener(private_output->output,
876                                                            &tdm_client_output_listener, private_output);
877         wl_display_roundtrip_queue(private_client->display, private_client->queue);
878
879         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
880
881         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
882                 wl_tdm_output_destroy(private_output->output);
883                 free(private_output);
884                 if (error)
885                         *error = TDM_ERROR_PROTOCOL_ERROR;
886                 pthread_mutex_unlock(&private_client->lock);
887                 return NULL;
888         }
889
890         LIST_ADDTAIL(&private_output->link, &private_client->output_list);
891
892         pthread_mutex_unlock(&private_client->lock);
893
894         return (tdm_client_output*)private_output;
895 }
896
897 tdm_error
898 tdm_client_output_add_change_handler(tdm_client_output *output,
899                                                                          tdm_client_output_change_handler func,
900                                                                          void *user_data)
901 {
902         tdm_private_client_output *private_output;
903         tdm_private_client *private_client;
904         tdm_client_output_handler_info *h = NULL;
905
906         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
907         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
908
909         private_output = (tdm_private_client_output*)output;
910         private_client = private_output->private_client;
911
912         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
913                 if (h->func == func && h->user_data == user_data) {
914                         TDM_ERR("can't add twice");
915                         return TDM_ERROR_BAD_REQUEST;
916                 }
917         }
918
919         h = calloc(1, sizeof *h);
920         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
921
922         pthread_mutex_lock(&private_client->lock);
923
924         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
925                 free(h);
926                 pthread_mutex_unlock(&private_client->lock);
927                 return TDM_ERROR_PROTOCOL_ERROR;
928         }
929
930         if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
931                 wl_tdm_output_watch_output_changes(private_output->output, 1);
932                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
933
934                 /* TODO: this is very tricky.
935                  * If a client adds the change_handler, we might be able to guess that
936                  * the client will watch the tdm client's fd and handle tdm events in
937                  * event loop. Otherwise, we CAN'T make sure if a client has event loop
938                  * which handles tdm events.
939                  */
940                 private_output->watch_output_changes = 1;
941         }
942
943         h->private_output = private_output;
944         h->func = func;
945         h->user_data = user_data;
946         LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
947         LIST_INITHEAD(&h->call_link);
948
949         pthread_mutex_unlock(&private_client->lock);
950
951         return TDM_ERROR_NONE;
952 }
953
954 void
955 tdm_client_output_remove_change_handler(tdm_client_output *output,
956                                                                                 tdm_client_output_change_handler func,
957                                                                                 void *user_data)
958 {
959         tdm_private_client_output *private_output;
960         tdm_private_client *private_client;
961         tdm_client_output_handler_info *h = NULL;
962
963         TDM_RETURN_IF_FAIL(output != NULL);
964         TDM_RETURN_IF_FAIL(func != NULL);
965
966         private_output = (tdm_private_client_output*)output;
967         private_client = private_output->private_client;
968
969         pthread_mutex_lock(&private_client->lock);
970
971         LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
972                 if (h->func != func || h->user_data != user_data)
973                         continue;
974
975                 LIST_DEL(&h->link);
976                 free(h);
977
978                 if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
979                         private_output->watch_output_changes = 0;
980                         if (!CHECK_WL_PROTOCOL_ERROR(private_client)) {
981                                 wl_tdm_output_watch_output_changes(private_output->output, 0);
982                                 wl_display_roundtrip_queue(private_client->display, private_client->queue);
983                         }
984                 }
985
986                 pthread_mutex_unlock(&private_client->lock);
987
988                 return;
989         }
990
991         pthread_mutex_unlock(&private_client->lock);
992 }
993
994 tdm_error
995 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
996 {
997         tdm_private_client_output *private_output;
998         tdm_private_client *private_client;
999
1000         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1001         TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
1002
1003         private_output = (tdm_private_client_output*)output;
1004         private_client = private_output->private_client;
1005
1006         pthread_mutex_lock(&private_client->lock);
1007
1008         if (private_output->watch_output_changes) {
1009                 *refresh = private_output->refresh;
1010                 pthread_mutex_unlock(&private_client->lock);
1011                 return TDM_ERROR_NONE;
1012         }
1013
1014         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1015                 pthread_mutex_unlock(&private_client->lock);
1016                 return TDM_ERROR_PROTOCOL_ERROR;
1017         }
1018
1019         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1020         wl_tdm_output_get_mode(private_output->output);
1021         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1022         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1023
1024         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1025                 pthread_mutex_unlock(&private_client->lock);
1026                 return TDM_ERROR_PROTOCOL_ERROR;
1027         }
1028
1029         *refresh = private_output->refresh;
1030
1031         pthread_mutex_unlock(&private_client->lock);
1032
1033         return TDM_ERROR_NONE;
1034 }
1035
1036 tdm_error
1037 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
1038 {
1039         tdm_private_client_output *private_output;
1040         tdm_private_client *private_client;
1041
1042         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1043         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
1044
1045         private_output = (tdm_private_client_output*)output;
1046         private_client = private_output->private_client;
1047
1048         pthread_mutex_lock(&private_client->lock);
1049
1050         if (private_output->watch_output_changes) {
1051                 *status = private_output->connection;
1052                 pthread_mutex_unlock(&private_client->lock);
1053                 return TDM_ERROR_NONE;
1054         }
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_connection(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         *status = private_output->connection;
1072
1073         pthread_mutex_unlock(&private_client->lock);
1074
1075         return TDM_ERROR_NONE;
1076 }
1077
1078 tdm_error
1079 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
1080 {
1081         tdm_private_client_output *private_output;
1082         tdm_private_client *private_client;
1083
1084         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
1085         TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
1086
1087         private_output = (tdm_private_client_output*)output;
1088         private_client = private_output->private_client;
1089
1090         if (private_output->watch_output_changes) {
1091                 *dpms = private_output->dpms;
1092                 return TDM_ERROR_NONE;
1093         }
1094
1095         pthread_mutex_lock(&private_client->lock);
1096
1097         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1098                 pthread_mutex_unlock(&private_client->lock);
1099                 return TDM_ERROR_PROTOCOL_ERROR;
1100         }
1101
1102         wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
1103         wl_tdm_output_get_dpms(private_output->output);
1104         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1105         wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
1106
1107         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1108                 pthread_mutex_unlock(&private_client->lock);
1109                 return TDM_ERROR_PROTOCOL_ERROR;
1110         }
1111
1112         *dpms = private_output->dpms;
1113
1114         pthread_mutex_unlock(&private_client->lock);
1115
1116         return TDM_ERROR_NONE;
1117 }
1118
1119 tdm_client_vblank*
1120 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
1121 {
1122         tdm_private_client *private_client;
1123         tdm_private_client_output *private_output;
1124         tdm_private_client_vblank *private_vblank;
1125         struct wl_proxy *wrapper;
1126
1127         if (error)
1128                 *error = TDM_ERROR_NONE;
1129
1130         if (!output) {
1131                 TDM_ERR("'!output' failed");
1132                 if (error)
1133                         *error = TDM_ERROR_INVALID_PARAMETER;
1134                 return NULL;
1135         }
1136
1137         private_output = (tdm_private_client_output*)output;
1138         private_client = private_output->private_client;
1139
1140         pthread_mutex_lock(&private_client->lock);
1141
1142         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1143                 if (error)
1144                         *error = TDM_ERROR_PROTOCOL_ERROR;
1145                 pthread_mutex_unlock(&private_client->lock);
1146                 return NULL;
1147         }
1148
1149         wrapper = wl_proxy_create_wrapper(private_output->output);
1150         if (!wrapper) {
1151                 TDM_ERR("create output_wrapper failed");
1152                 if (error)
1153                         *error = TDM_ERROR_OUT_OF_MEMORY;
1154                 pthread_mutex_unlock(&private_client->lock);
1155                 return NULL;
1156         }
1157
1158         wl_proxy_set_queue(wrapper, private_client->queue);
1159
1160         private_vblank = calloc(1, sizeof *private_vblank);
1161         if (!private_vblank) {
1162                 /* LCOV_EXCL_START */
1163
1164                 TDM_ERR("alloc failed");
1165                 wl_proxy_wrapper_destroy(wrapper);
1166                 if (error)
1167                         *error = TDM_ERROR_OUT_OF_MEMORY;
1168                 pthread_mutex_unlock(&private_client->lock);
1169                 return NULL;
1170
1171                 /* LCOV_EXCL_STOP */
1172         }
1173
1174         private_vblank->private_output = private_output;
1175
1176         private_vblank->vblank = wl_tdm_output_create_vblank((struct wl_tdm_output*)wrapper);
1177         wl_proxy_wrapper_destroy(wrapper);
1178         if (!private_vblank->vblank) {
1179                 /* LCOV_EXCL_START */
1180
1181                 TDM_ERR("couldn't create vblank resource");
1182                 free(private_vblank);
1183                 if (error)
1184                         *error = TDM_ERROR_OUT_OF_MEMORY;
1185                 pthread_mutex_unlock(&private_client->lock);
1186                 return NULL;
1187
1188                 /* LCOV_EXCL_STOP */
1189         }
1190
1191         /* initial value */
1192         private_vblank->fps = private_output->refresh;
1193         private_vblank->offset = 0;
1194         private_vblank->enable_fake = 0;
1195
1196         LIST_INITHEAD(&private_vblank->wait_list);
1197
1198         wl_tdm_vblank_add_listener(private_vblank->vblank,
1199                                                            &tdm_client_vblank_listener, private_vblank);
1200         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1201
1202         wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
1203
1204         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1205                 wl_tdm_vblank_destroy(private_vblank->vblank);
1206                 free(private_vblank);
1207                 if (error)
1208                         *error = TDM_ERROR_PROTOCOL_ERROR;
1209                 pthread_mutex_unlock(&private_client->lock);
1210                 return NULL;
1211         }
1212
1213         LIST_ADDTAIL(&private_vblank->link, &private_output->vblank_list);
1214
1215         pthread_mutex_unlock(&private_client->lock);
1216
1217         return (tdm_client_vblank*)private_vblank;
1218 }
1219
1220 void
1221 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
1222 {
1223         tdm_private_client_vblank *private_vblank;
1224         tdm_private_client *private_client;
1225         tdm_client_wait_info *w = NULL, *ww = NULL;
1226
1227         TDM_RETURN_IF_FAIL(vblank != NULL);
1228
1229         private_vblank = vblank;
1230         private_client = private_vblank->private_output->private_client;
1231
1232         pthread_mutex_lock(&private_client->lock);
1233
1234         LIST_DEL(&private_vblank->link);
1235
1236         LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
1237                 LIST_DEL(&w->link);
1238                 free(w);
1239         }
1240
1241         wl_tdm_vblank_destroy(private_vblank->vblank);
1242
1243         free(private_vblank);
1244
1245         pthread_mutex_unlock(&private_client->lock);
1246 }
1247
1248 tdm_error
1249 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
1250 {
1251         tdm_private_client_vblank *private_vblank;
1252         tdm_private_client *private_client;
1253
1254         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1255
1256         private_vblank = vblank;
1257         private_client = private_vblank->private_output->private_client;
1258
1259         pthread_mutex_lock(&private_client->lock);
1260
1261         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1262                 pthread_mutex_unlock(&private_client->lock);
1263                 return TDM_ERROR_PROTOCOL_ERROR;
1264         }
1265
1266         if (!name)
1267                 name = TDM_VBLANK_DEFAULT_NAME;
1268
1269         strncpy(private_vblank->name, name, TDM_NAME_LEN - 1);
1270         private_vblank->name[TDM_NAME_LEN - 1] = '\0';
1271
1272         wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
1273
1274         pthread_mutex_unlock(&private_client->lock);
1275
1276         return TDM_ERROR_NONE;
1277 }
1278
1279 tdm_error
1280 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
1281 {
1282         tdm_private_client_vblank *private_vblank;
1283         tdm_private_client *private_client;
1284
1285         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1286
1287         private_vblank = vblank;
1288         private_client = private_vblank->private_output->private_client;
1289
1290         pthread_mutex_lock(&private_client->lock);
1291         private_vblank->sync = sync;
1292         pthread_mutex_unlock(&private_client->lock);
1293
1294         return TDM_ERROR_NONE;
1295 }
1296
1297 tdm_error
1298 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
1299 {
1300         tdm_private_client_vblank *private_vblank;
1301         tdm_private_client *private_client;
1302
1303         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1304         TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
1305
1306         private_vblank = vblank;
1307         private_client = private_vblank->private_output->private_client;
1308
1309         pthread_mutex_lock(&private_client->lock);
1310
1311         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1312                 pthread_mutex_unlock(&private_client->lock);
1313                 return TDM_ERROR_PROTOCOL_ERROR;
1314         }
1315
1316         if (private_vblank->fps == fps) {
1317                 pthread_mutex_unlock(&private_client->lock);
1318                 return TDM_ERROR_NONE;
1319         }
1320
1321         private_vblank->fps = fps;
1322
1323         wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
1324
1325         pthread_mutex_unlock(&private_client->lock);
1326
1327         return TDM_ERROR_NONE;
1328 }
1329
1330 tdm_error
1331 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
1332 {
1333         tdm_private_client_vblank *private_vblank;
1334         tdm_private_client *private_client;
1335
1336         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1337
1338         private_vblank = vblank;
1339         TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
1340
1341         private_client = private_vblank->private_output->private_client;
1342
1343         pthread_mutex_lock(&private_client->lock);
1344
1345         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1346                 pthread_mutex_unlock(&private_client->lock);
1347                 return TDM_ERROR_PROTOCOL_ERROR;
1348         }
1349
1350         if (private_vblank->offset == offset_ms) {
1351                 pthread_mutex_unlock(&private_client->lock);
1352                 return TDM_ERROR_NONE;
1353         }
1354
1355         private_vblank->offset = offset_ms;
1356
1357         wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
1358
1359         pthread_mutex_unlock(&private_client->lock);
1360
1361         return TDM_ERROR_NONE;
1362 }
1363
1364 tdm_error
1365 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
1366 {
1367         tdm_private_client_vblank *private_vblank;
1368         tdm_private_client *private_client;
1369
1370         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1371
1372         private_vblank = vblank;
1373         private_client = private_vblank->private_output->private_client;
1374
1375         pthread_mutex_lock(&private_client->lock);
1376
1377         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1378                 pthread_mutex_unlock(&private_client->lock);
1379                 return TDM_ERROR_PROTOCOL_ERROR;
1380         }
1381
1382         if (private_vblank->enable_fake == enable_fake) {
1383                 pthread_mutex_unlock(&private_client->lock);
1384                 return TDM_ERROR_NONE;
1385         }
1386
1387         private_vblank->enable_fake = enable_fake;
1388
1389         wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
1390
1391         pthread_mutex_unlock(&private_client->lock);
1392
1393         return TDM_ERROR_NONE;
1394 }
1395
1396 tdm_error
1397 tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_client_vblank_handler func, void *user_data)
1398 {
1399         tdm_private_client *private_client;
1400         tdm_private_client_output *private_output;
1401         tdm_private_client_vblank *private_vblank;
1402         tdm_client_wait_info *w;
1403         struct timespec tp;
1404         unsigned int req_sec, req_usec;
1405         int ret = 0;
1406
1407         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1408         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1409         /* can't support "interval 0" and "getting current_msc" things because
1410          * there is a socket communication between TDM client and server. It's impossible
1411          * to return the current msc or sequence immediately.
1412          */
1413         TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER);
1414
1415         private_vblank = vblank;
1416         private_output = private_vblank->private_output;
1417         private_client = private_output->private_client;
1418
1419         pthread_mutex_lock(&private_client->lock);
1420
1421         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1422                 pthread_mutex_unlock(&private_client->lock);
1423                 return TDM_ERROR_PROTOCOL_ERROR;
1424         }
1425
1426         if (!private_vblank->started)
1427                 private_vblank->started = 1;
1428
1429         if (!private_vblank->enable_fake) {
1430                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1431                         TDM_ERR("output disconnected");
1432                         pthread_mutex_unlock(&private_client->lock);
1433                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1434                 }
1435                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1436                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1437                         pthread_mutex_unlock(&private_client->lock);
1438                         return TDM_ERROR_DPMS_OFF;
1439                 }
1440         }
1441
1442         w = calloc(1, sizeof *w);
1443         if (!w) {
1444                 /* LCOV_EXCL_START */
1445
1446                 TDM_ERR("alloc failed");
1447                 pthread_mutex_unlock(&private_client->lock);
1448                 return TDM_ERROR_OUT_OF_MEMORY;
1449
1450                 /* LCOV_EXCL_STOP */
1451         }
1452
1453         w->private_vblank = private_vblank;
1454         w->func = func;
1455         w->user_data = user_data;
1456
1457         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1458         LIST_INITHEAD(&w->call_link);
1459
1460         clock_gettime(CLOCK_MONOTONIC, &tp);
1461         req_sec = (unsigned int)tp.tv_sec;
1462         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1463
1464         w->req_id = ++private_output->req_id;
1465         w->req_time = TDM_TIME(req_sec, req_usec);
1466         w->need_free = (private_vblank->sync) ? 0 : 1;
1467
1468         wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec);
1469
1470         if (private_vblank->enable_ttrace)
1471                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1472
1473         TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)",
1474                         vblank, interval, w->req_id, w->req_time);
1475
1476         private_vblank->req_time = w->req_time;
1477
1478         if (private_vblank->last_time >= w->req_time)
1479                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1480
1481         if (!private_vblank->sync) {
1482                 wl_display_flush(private_client->display);
1483                 pthread_mutex_unlock(&private_client->lock);
1484                 return TDM_ERROR_NONE;
1485         }
1486
1487         /* LCOV_EXCL_START */
1488
1489         while (ret != -1 && !w->need_free)
1490                 ret = wl_display_dispatch(private_client->display);
1491
1492         clock_gettime(CLOCK_MONOTONIC, &tp);
1493         TDM_DBG("block during %d us",
1494                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1495                         - (req_sec * 1000000 + req_usec));
1496
1497         LIST_DEL(&w->link);
1498         free(w);
1499
1500         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1501                 pthread_mutex_unlock(&private_client->lock);
1502                 return TDM_ERROR_PROTOCOL_ERROR;
1503         }
1504
1505         pthread_mutex_unlock(&private_client->lock);
1506
1507         return TDM_ERROR_NONE;
1508
1509         /* LCOV_EXCL_STOP */
1510 }
1511
1512 tdm_error
1513 tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
1514                                                    tdm_client_vblank_handler func, void *user_data)
1515 {
1516         tdm_private_client *private_client;
1517         tdm_private_client_output *private_output;
1518         tdm_private_client_vblank *private_vblank;
1519         tdm_client_wait_info *w;
1520         struct timespec tp;
1521         unsigned int req_sec, req_usec;
1522         int ret = 0;
1523
1524         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
1525         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
1526
1527         private_vblank = vblank;
1528         private_output = private_vblank->private_output;
1529         private_client = private_output->private_client;
1530
1531         pthread_mutex_lock(&private_client->lock);
1532
1533         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1534                 pthread_mutex_unlock(&private_client->lock);
1535                 return TDM_ERROR_PROTOCOL_ERROR;
1536         }
1537
1538         if (!private_vblank->started)
1539                 private_vblank->started = 1;
1540
1541         if (!private_vblank->enable_fake) {
1542                 if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
1543                         TDM_ERR("output disconnected");
1544                         pthread_mutex_unlock(&private_client->lock);
1545                         return TDM_ERROR_OUTPUT_DISCONNECTED;
1546                 }
1547                 if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
1548                         TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
1549                         pthread_mutex_unlock(&private_client->lock);
1550                         return TDM_ERROR_DPMS_OFF;
1551                 }
1552         }
1553
1554         w = calloc(1, sizeof *w);
1555         if (!w) {
1556                 /* LCOV_EXCL_START */
1557
1558                 TDM_ERR("alloc failed");
1559                 pthread_mutex_unlock(&private_client->lock);
1560                 return TDM_ERROR_OUT_OF_MEMORY;
1561
1562                 /* LCOV_EXCL_STOP */
1563         }
1564
1565         w->private_vblank = private_vblank;
1566         w->func = func;
1567         w->user_data = user_data;
1568
1569         LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
1570         LIST_INITHEAD(&w->call_link);
1571
1572         clock_gettime(CLOCK_MONOTONIC, &tp);
1573         req_sec = (unsigned int)tp.tv_sec;
1574         req_usec = (unsigned int)(tp.tv_nsec / 1000);
1575
1576         w->req_id = ++private_output->req_id;
1577         w->req_time = TDM_TIME(req_sec, req_usec);
1578         w->need_free = (private_vblank->sync) ? 0 : 1;
1579
1580         wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec);
1581
1582         if (private_vblank->enable_ttrace)
1583                 TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
1584
1585         TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)",
1586                         vblank, sequence, w->req_id, w->req_time);
1587
1588         private_vblank->req_time = w->req_time;
1589
1590         if (private_vblank->last_time >= w->req_time)
1591                 TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time);
1592
1593         if (!private_vblank->sync) {
1594                 wl_display_flush(private_client->display);
1595                 pthread_mutex_unlock(&private_client->lock);
1596                 return TDM_ERROR_NONE;
1597         }
1598
1599         /* LCOV_EXCL_START */
1600
1601         while (ret != -1 && !w->need_free)
1602                 ret = wl_display_dispatch(private_client->display);
1603
1604         clock_gettime(CLOCK_MONOTONIC, &tp);
1605         TDM_DBG("block during %d us",
1606                         ((unsigned int)(tp.tv_sec * 1000000) + (unsigned int)(tp.tv_nsec / 1000))
1607                         - (req_sec * 1000000 + req_usec));
1608
1609         LIST_DEL(&w->link);
1610         free(w);
1611
1612         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1613                 pthread_mutex_unlock(&private_client->lock);
1614                 return TDM_ERROR_PROTOCOL_ERROR;
1615         }
1616
1617         pthread_mutex_unlock(&private_client->lock);
1618
1619         return TDM_ERROR_NONE;
1620
1621         /* LCOV_EXCL_STOP */
1622 }
1623
1624 unsigned int
1625 tdm_client_vblank_is_waiting(tdm_client_vblank *vblank)
1626 {
1627         tdm_private_client_vblank *private_vblank;
1628
1629         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, 0);
1630
1631         private_vblank = vblank;
1632
1633         return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0;
1634 }
1635
1636 static tbm_surface_h
1637 _tdm_client_voutput_create_surface_from_param(tbm_bufmgr bufmgr,
1638                                                          int is_fd,
1639                                                          int32_t width,
1640                                                          int32_t height,
1641                                                          uint32_t format,
1642                                                          int32_t bpp,
1643                                                          int32_t size,
1644                                                          int32_t num_plane,
1645                                                          struct wl_array *plane_buf_idx,
1646                                                          struct wl_array *plane_offset,
1647                                                          struct wl_array *plane_stride,
1648                                                          struct wl_array *plane_size,
1649                                                          uint32_t flags,
1650                                                          int32_t num_buf,
1651                                                          uint32_t buf0,
1652                                                          uint32_t buf1,
1653                                                          uint32_t buf2)
1654 {
1655         int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
1656         tbm_surface_info_s info = { 0, };
1657         tbm_bo bos[TBM_SURF_PLANE_MAX];
1658         int i, numPlane, numName;
1659         tbm_surface_h tbm_surface;
1660
1661         numPlane = tbm_surface_internal_get_num_planes(format);
1662         TDM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
1663
1664         info.width = width;
1665         info.height = height;
1666         info.format = format;
1667         info.bpp = bpp;
1668         info.size = size;
1669         info.num_planes = numPlane;
1670
1671         /*Fill plane info*/
1672         for (i = 0; i < numPlane; i++) {
1673                 info.planes[i].offset = *TDM_ARRAY_NTH_DATA(plane_offset, int32_t, i);
1674                 info.planes[i].stride = *TDM_ARRAY_NTH_DATA(plane_stride, int32_t, i);
1675                 info.planes[i].size = *TDM_ARRAY_NTH_DATA(plane_size, int32_t, i);
1676         }
1677
1678         /*Fill buffer*/
1679         numName = num_buf;
1680         names[0] = buf0;
1681         names[1] = buf1;
1682         names[2] = buf2;
1683
1684         for (i = 0; i < numName; i++) {
1685                 if (is_fd)
1686                         bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
1687                 else
1688                         bos[i] = tbm_bo_import(bufmgr, names[i]);
1689         }
1690
1691         tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
1692         if (tbm_surface == NULL) {
1693                 if (is_fd) {
1694                         close(buf0);
1695                         close(buf1);
1696                         close(buf2);
1697                 }
1698                 return NULL;
1699         }
1700
1701         if (is_fd) {
1702                 close(buf0);
1703                 close(buf1);
1704                 close(buf2);
1705         }
1706
1707         for (i = 0; i < numName; i++)
1708                 tbm_bo_unref(bos[i]);
1709
1710         return tbm_surface;
1711 }
1712 static void
1713 tdm_client_voutput_cb_buffer_import_with_id(void *data,
1714                 struct wl_tdm_voutput *wl_voutput,
1715                 struct wl_buffer *wl_buffer,
1716                 int32_t width,
1717                 int32_t height,
1718                 uint32_t format,
1719                 int32_t bpp,
1720                 int32_t size,
1721                 int32_t num_plane,
1722                 struct wl_array *plane_buf_idx,
1723                 struct wl_array *plane_offset,
1724                 struct wl_array *plane_stride,
1725                 struct wl_array *plane_size,
1726                 uint32_t flags,
1727                 int32_t num_buf,
1728                 uint32_t buf0,
1729                 uint32_t buf1,
1730                 uint32_t buf2)
1731 {
1732         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1733         tdm_private_client_buffer *buffer = NULL;
1734         tbm_surface_h tbm_surface;
1735
1736         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1737
1738         buffer = calloc(1, sizeof *buffer);
1739         TDM_RETURN_IF_FAIL(buffer != NULL);
1740
1741         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 0,
1742                               width, height, format, bpp, size,
1743                               num_plane,
1744                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1745                               0,
1746                               num_buf,
1747                               buf0, buf1, buf2);
1748         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1749
1750         tbm_surface_internal_ref(tbm_surface);
1751         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1752
1753         buffer->wl_buffer = wl_buffer;
1754
1755         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1756
1757         return;
1758
1759 fail:
1760         if (buffer)
1761                 free(buffer);
1762
1763         if (wl_buffer)
1764                 wl_buffer_destroy(wl_buffer);
1765 }
1766
1767 static void
1768 tdm_client_voutput_cb_buffer_import_with_fd(void *data,
1769                 struct wl_tdm_voutput *wl_voutput,
1770                 struct wl_buffer *wl_buffer,
1771                 int32_t width,
1772                 int32_t height,
1773                 uint32_t format,
1774                 int32_t bpp,
1775                 int32_t size,
1776                 int32_t num_plane,
1777                 struct wl_array *plane_buf_idx,
1778                 struct wl_array *plane_offset,
1779                 struct wl_array *plane_stride,
1780                 struct wl_array *plane_size,
1781                 uint32_t flags,
1782                 int32_t num_buf,
1783                 int32_t buf0,
1784                 int32_t buf1,
1785                 int32_t buf2)
1786 {
1787         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1788         tdm_private_client_buffer *buffer = NULL;
1789         tbm_surface_h tbm_surface;
1790
1791         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1792
1793         buffer = calloc(1, sizeof *buffer);
1794         TDM_RETURN_IF_FAIL(buffer != NULL);
1795
1796         tbm_surface = _tdm_client_voutput_create_surface_from_param(private_voutput->bufmgr, 1,
1797                               width, height, format, bpp, size,
1798                               num_plane,
1799                               plane_buf_idx, plane_offset, plane_stride, plane_size,
1800                               0,
1801                               num_buf,
1802                               buf0, buf1, buf2);
1803         TDM_GOTO_IF_FAIL(tbm_surface != NULL, fail);
1804
1805         tbm_surface_internal_ref(tbm_surface);
1806         wl_buffer_set_user_data(wl_buffer, tbm_surface);
1807
1808         buffer->wl_buffer = wl_buffer;
1809
1810         LIST_ADDTAIL(&buffer->link, &private_voutput->buffer_list);
1811
1812         return;
1813
1814 fail:
1815         if (buffer)
1816                 free(buffer);
1817
1818         if (wl_buffer)
1819                 wl_buffer_destroy(wl_buffer);
1820 }
1821
1822 static void
1823 tdm_client_voutput_cb_buffer_destroy(void *data,
1824                 struct wl_tdm_voutput *wl_voutput,
1825                 struct wl_buffer *wl_buffer)
1826 {
1827         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)data;
1828         tdm_private_client_buffer *cb = NULL, *cbb = NULL;
1829         tbm_surface_h tbm_surface = NULL;
1830
1831         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1832
1833         LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
1834                 if (wl_buffer == cb->wl_buffer) {
1835                         LIST_DEL(&cb->link);
1836
1837                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(wl_buffer);
1838                         if (tbm_surface)
1839                                 tbm_surface_internal_unref(tbm_surface);
1840
1841                         wl_buffer_set_user_data(wl_buffer, NULL);
1842                         wl_buffer_destroy(wl_buffer);
1843
1844                         free(cb);
1845
1846                         break;
1847                 }
1848         }
1849
1850         return;
1851 }
1852
1853 void
1854 tdm_client_voutput_cb_commit(void *data, struct wl_tdm_voutput *wl_voutput)
1855 {
1856         tdm_private_client_voutput *private_voutput;
1857         tdm_private_client *private_client;
1858         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
1859         struct list_head call_list;
1860
1861         private_voutput = (tdm_private_client_voutput *)data;
1862         TDM_RETURN_IF_FAIL(private_voutput != NULL);
1863
1864         private_client = private_voutput->base.private_client;
1865
1866         LIST_INITHEAD(&call_list);
1867
1868         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
1869                 LIST_ADDTAIL(&h->call_link, &call_list);
1870         }
1871
1872         pthread_mutex_unlock(&private_client->lock);
1873         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
1874                 if (h->func)
1875                         h->func(private_voutput, h->user_data);
1876         }
1877         pthread_mutex_lock(&private_client->lock);
1878 }
1879
1880 void
1881 tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg)
1882 {
1883         tdm_private_client_voutput *private_voutput = data;
1884
1885         private_voutput->msg = msg;
1886 }
1887
1888 static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = {
1889         tdm_client_voutput_cb_buffer_import_with_id,
1890         tdm_client_voutput_cb_buffer_import_with_fd,
1891         tdm_client_voutput_cb_buffer_destroy,
1892         tdm_client_voutput_cb_commit,
1893         tdm_client_voutput_cb_ack_message
1894 };
1895
1896 tdm_client_voutput *
1897 tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error)
1898 {
1899         tdm_private_client *private_client;
1900         tdm_private_client_output *private_output;
1901         tdm_private_client_voutput *private_voutput;
1902         struct wl_proxy *wrapper;
1903
1904         if (error)
1905                 *error = TDM_ERROR_NONE;
1906
1907         if (!client) {
1908                 TDM_ERR("'!client' failed");
1909                 if (error)
1910                         *error = TDM_ERROR_INVALID_PARAMETER;
1911                 return NULL;
1912         }
1913
1914         if (!name) {
1915                 TDM_ERR("'!name' failed");
1916                 if (error)
1917                         *error = TDM_ERROR_INVALID_PARAMETER;
1918                 return NULL;
1919         }
1920
1921         private_client = (tdm_private_client *)client;
1922
1923         pthread_mutex_lock(&private_client->lock);
1924
1925         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
1926                 if (error)
1927                         *error = TDM_ERROR_PROTOCOL_ERROR;
1928                 pthread_mutex_unlock(&private_client->lock);
1929                 return NULL;
1930         }
1931
1932         LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
1933                 if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
1934                         if (error)
1935                                 *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type.
1936                         pthread_mutex_unlock(&private_client->lock);
1937                         return NULL;
1938                 }
1939         }
1940
1941         wrapper = wl_proxy_create_wrapper(private_client->tdm);
1942         if (!wrapper) {
1943                 TDM_ERR("create virtual output wrapper failed");
1944                 if (error)
1945                         *error = TDM_ERROR_OUT_OF_MEMORY;
1946                 pthread_mutex_unlock(&private_client->lock);
1947                 return NULL;
1948         }
1949
1950         wl_proxy_set_queue(wrapper, private_client->queue);
1951
1952         private_voutput = calloc(1, sizeof *private_voutput);
1953         if (!private_voutput) {
1954                 /* LOCV_EXCL_START */
1955                 wl_proxy_wrapper_destroy(wrapper);
1956                 TDM_ERR("alloc failed");
1957                 if (error)
1958                         *error = TDM_ERROR_OUT_OF_MEMORY;
1959                 pthread_mutex_unlock(&private_client->lock);
1960                 return NULL;
1961                 /* LOCV_EXCL_STOP */
1962         }
1963
1964         private_voutput->bufmgr = tbm_bufmgr_init(-1);
1965         if (private_voutput->bufmgr == NULL) {
1966                 /* LCOV_EXCL_START */
1967                 TDM_ERR("fail tbm_bufmgr_init");
1968                 free(private_voutput);
1969                 if (error)
1970                         *error = TDM_ERROR_OUT_OF_MEMORY;
1971                 pthread_mutex_unlock(&private_client->lock);
1972                 return NULL;
1973                 /* LCOV_EXCL_STOP */
1974         }
1975
1976         LIST_INITHEAD(&private_voutput->commit_handler_list);
1977         LIST_INITHEAD(&private_voutput->buffer_list);
1978
1979         private_voutput->base.private_client = private_client;
1980
1981         private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name);
1982         wl_proxy_wrapper_destroy(wrapper);
1983         if (!private_voutput->wl_voutput) {
1984                 /* LCOV_EXCL_START */
1985                 TDM_ERR("couldn't create voutput resource");
1986                 free(private_voutput);
1987                 if (error)
1988                         *error = TDM_ERROR_OUT_OF_MEMORY;
1989                 pthread_mutex_unlock(&private_client->lock);
1990                 return NULL;
1991                 /* LCOV_EXCL_STOP */
1992         }
1993
1994         wl_tdm_voutput_add_listener(private_voutput->wl_voutput,
1995                                                                 &tdm_client_voutput_lisntener, private_voutput);
1996         wl_display_roundtrip_queue(private_client->display, private_client->queue);
1997
1998         wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL);
1999
2000         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2001                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2002                 free(private_voutput);
2003                 if (error)
2004                         *error = TDM_ERROR_PROTOCOL_ERROR;
2005                 pthread_mutex_unlock(&private_client->lock);
2006                 return NULL;
2007         }
2008
2009         if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED)
2010         {
2011                 wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2012                 free(private_voutput);
2013                 if (error)
2014                         *error = TDM_ERROR_PROTOCOL_ERROR;      // FIXME add new error type.
2015                 pthread_mutex_unlock(&private_client->lock);
2016                 return NULL;
2017         }
2018
2019         pthread_mutex_unlock(&private_client->lock);
2020
2021         return (tdm_client_voutput *)private_voutput;
2022 }
2023
2024 void
2025 tdm_client_voutput_destroy(tdm_client_voutput *voutput)
2026 {
2027         tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput;
2028         tdm_client_voutput_commit_handler_info *h = NULL, *hh = NULL;
2029
2030         if (!private_voutput)
2031                 return;
2032
2033         if (!(LIST_IS_EMPTY(&private_voutput->buffer_list))) {
2034                 tdm_private_client_buffer *cb = NULL, *cbb = NULL;
2035
2036                 LIST_FOR_EACH_ENTRY_SAFE(cb, cbb, &private_voutput->buffer_list, link) {
2037                         tbm_surface_h tbm_surface = NULL;
2038
2039                         if (!cb) continue;
2040
2041                         LIST_DEL(&cb->link);
2042
2043                         tbm_surface = (tbm_surface_h)wl_buffer_get_user_data(cb->wl_buffer);
2044                         if (tbm_surface)
2045                                 tbm_surface_internal_unref(tbm_surface);
2046
2047                         wl_buffer_set_user_data(cb->wl_buffer, NULL);
2048                         wl_buffer_destroy(cb->wl_buffer);
2049
2050                         free(cb);
2051                 }
2052         }
2053
2054         if (private_voutput->bufmgr)
2055                 tbm_bufmgr_deinit(private_voutput->bufmgr);
2056
2057         if (private_voutput->available_modes.modes)
2058                 free(private_voutput->available_modes.modes);
2059
2060         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_voutput->commit_handler_list, link) {
2061                 LIST_DEL(&h->link);
2062                 free(h);
2063         }
2064
2065         wl_tdm_voutput_destroy(private_voutput->wl_voutput);
2066
2067         free(private_voutput);
2068 }
2069
2070 tdm_error
2071 tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count)
2072 {
2073         tdm_private_client_voutput *private_voutput;
2074
2075         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2076
2077         if ((count > 0) && (modes == NULL))
2078                 return TDM_ERROR_INVALID_PARAMETER;
2079
2080         private_voutput = (tdm_private_client_voutput *)voutput;
2081
2082         if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2083                 return TDM_ERROR_BAD_REQUEST;
2084
2085         if (private_voutput->available_modes.modes)
2086                 free(private_voutput->available_modes.modes);
2087
2088         private_voutput->available_modes.count = count;
2089
2090         if (count != 0)
2091         {
2092                 private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode));
2093                 memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count);
2094         }
2095
2096         return TDM_ERROR_NONE;
2097 }
2098
2099 tdm_error
2100 tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight)
2101 {
2102         tdm_private_client_voutput *private_voutput;
2103
2104         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2105         TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER);
2106         TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER);
2107
2108         private_voutput = (tdm_private_client_voutput *)voutput;
2109
2110         if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED)
2111                 return TDM_ERROR_BAD_REQUEST;
2112
2113         private_voutput->mmwidth = mmWidth;
2114         private_voutput->mmheight = mmHeight;
2115
2116         return TDM_ERROR_NONE;
2117 }
2118
2119 tdm_error
2120 tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput,
2121                                                                           tdm_client_voutput_commit_handler func,
2122                                                                           void *user_data)
2123 {
2124         tdm_private_client_voutput *private_voutput;
2125         tdm_private_client *private_client;
2126         tdm_client_voutput_commit_handler_info *h = NULL;
2127
2128         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2129         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
2130
2131         private_voutput = (tdm_private_client_voutput *)voutput;
2132         private_client = private_voutput->base.private_client;
2133
2134         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2135                 if (h->func == func && h->user_data == user_data) {
2136                         TDM_ERR("can't add twice");
2137                         return TDM_ERROR_BAD_REQUEST;
2138                 }
2139         }
2140
2141         h = calloc(1, sizeof *h);
2142         TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
2143
2144         pthread_mutex_lock(&private_client->lock);
2145
2146         if (CHECK_WL_PROTOCOL_ERROR(private_client)) {
2147                 free(h);
2148                 pthread_mutex_unlock(&private_client->lock);
2149                 return TDM_ERROR_PROTOCOL_ERROR;
2150         }
2151
2152         h->private_voutput = private_voutput;
2153         h->func = func;
2154         h->user_data = user_data;
2155         LIST_ADDTAIL(&h->link, &private_voutput->commit_handler_list);
2156         LIST_INITHEAD(&h->call_link);
2157
2158         pthread_mutex_unlock(&private_client->lock);
2159
2160         return TDM_ERROR_NONE;
2161 }
2162
2163 void
2164 tdm_client_voutput_remove_commit_handler(tdm_client_voutput *voutput,
2165                                                                                  tdm_client_voutput_commit_handler func,
2166                                                                                  void *user_data)
2167 {
2168         tdm_private_client_voutput *private_voutput;
2169         tdm_private_client *private_client;
2170         tdm_client_voutput_commit_handler_info *h = NULL;
2171
2172         TDM_RETURN_IF_FAIL(voutput != NULL);
2173         TDM_RETURN_IF_FAIL(func != NULL);
2174
2175         private_voutput = (tdm_private_client_voutput *)voutput;
2176         private_client = private_voutput->base.private_client;
2177
2178         pthread_mutex_lock(&private_client->lock);
2179
2180         LIST_FOR_EACH_ENTRY(h, &private_voutput->commit_handler_list, link) {
2181                 if (h->func != func || h->user_data != user_data)
2182                         continue;
2183
2184                 LIST_DEL(&h->link);
2185                 free(h);
2186
2187                 pthread_mutex_unlock(&private_client->lock);
2188         }
2189
2190         pthread_mutex_unlock(&private_client->lock);
2191 }
2192
2193 tdm_error
2194 tdm_client_voutput_commit_done(tdm_client_voutput *voutput)
2195 {
2196         tdm_private_client_voutput *private_voutput;
2197
2198         TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER);
2199
2200         private_voutput = (tdm_private_client_voutput *)voutput;
2201         wl_tdm_voutput_commit_done(private_voutput->wl_voutput);
2202
2203         return TDM_ERROR_NONE;
2204 }
2205
2206 tdm_client_output *
2207 tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error)
2208 {
2209         tdm_private_client_voutput *private_voutput;
2210
2211         if (error)
2212                 *error = TDM_ERROR_NONE;
2213
2214         if (!voutput)
2215         {
2216                 TDM_ERR("'!voutput' failed");
2217                 if (error)
2218                         *error = TDM_ERROR_INVALID_PARAMETER;
2219                 return NULL;
2220         }
2221
2222         private_voutput = (tdm_private_client_voutput *)voutput;
2223
2224         return &private_voutput->base;
2225 }
2226
2227 tdm_error
2228 tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count)
2229 {
2230         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2231         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
2232         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
2233
2234         return TDM_ERROR_NONE;
2235 }
2236
2237 tdm_error
2238 tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode)
2239 {
2240         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2241         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
2242
2243         return TDM_ERROR_NONE;
2244 }
2245
2246 void
2247 _tdm_client_voutput_send_available_modes(tdm_private_client_voutput *private_voutput)
2248 {
2249         tdm_client_output_mode *modes, *mode;
2250         struct wl_array array;
2251         int i, size;
2252
2253         modes = private_voutput->available_modes.modes;
2254         size = sizeof(tdm_client_output_mode);
2255
2256         wl_array_init(&array);
2257         for (i = 0; i < private_voutput->available_modes.count; i++) {
2258                 mode = wl_array_add(&array, size);
2259                 memcpy(mode, &modes[i], size);
2260         }
2261         wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, &array);
2262         wl_array_release(&array);
2263 }
2264
2265 tdm_error
2266 tdm_client_output_connect(tdm_client_output *output)
2267 {
2268         tdm_private_client_output *private_output;
2269         tdm_private_client_voutput *private_voutput;
2270
2271         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2272
2273         private_output = (tdm_private_client_output *)output;
2274         private_voutput = (tdm_private_client_voutput *)output;
2275
2276         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED,
2277                                                    TDM_ERROR_BAD_REQUEST);
2278
2279         private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED;
2280
2281         _tdm_client_voutput_send_available_modes(private_voutput);
2282
2283         wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight);
2284
2285         wl_tdm_voutput_connect(private_voutput->wl_voutput);
2286
2287         return TDM_ERROR_NONE;
2288 }
2289
2290 tdm_error
2291 tdm_client_output_disconnect(tdm_client_output *output)
2292 {
2293         tdm_private_client_voutput *private_voutput;
2294         tdm_private_client_output *private_output;
2295
2296         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
2297
2298         private_output = (tdm_private_client_output *)output;
2299         private_voutput = (tdm_private_client_voutput *)output;
2300
2301         TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED,
2302                                                    TDM_ERROR_BAD_REQUEST);
2303
2304         private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
2305
2306         wl_tdm_voutput_disconnect(private_voutput->wl_voutput);
2307
2308         return TDM_ERROR_NONE;
2309 }