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