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