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