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