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