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