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