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