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