fix syntax error
[platform/core/uifw/libtdm.git] / src / tdm_event_loop.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 "tdm_private.h"
41
42 typedef struct _tdm_event_loop_source_base {
43         struct list_head link;
44         tdm_private_display *private_display;
45         struct wl_event_source *wl_source;
46 } tdm_event_loop_source_base;
47
48 typedef struct _tdm_event_loop_source_fd {
49         tdm_event_loop_source_base base;
50         tdm_event_loop_fd_handler func;
51         void *user_data;
52 } tdm_event_loop_source_fd;
53
54 typedef struct _tdm_event_loop_source_timer {
55         tdm_event_loop_source_base base;
56         tdm_event_loop_timer_handler func;
57         void *user_data;
58 } tdm_event_loop_source_timer;
59
60 static tdm_private_loop *keep_private_loop;
61
62 static tdm_error
63 _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
64 {
65         tdm_private_module *private_module = (tdm_private_module*)user_data;
66         tdm_private_display *private_display;
67         tdm_func_display *func_display;
68         tdm_error ret;
69
70         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
71         TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_OPERATION_FAILED);
72
73         if (tdm_debug_module & TDM_DEBUG_EVENT)
74                 TDM_INFO("backend fd(%d) event happens", private_module->fd);
75
76         if (private_module->use_hal_tdm) {
77                 tdm_private_module *current_module;
78                 private_display = private_module->private_display;
79                 current_module = private_display->current_module;
80                 private_display->current_module = private_module;
81                 ret = (tdm_error)hal_tdm_display_handle_events(private_module->htdm_dpy);
82                 if (ret == TDM_ERROR_NONE)
83                         private_display->current_module = NULL;
84                 else
85                         private_display->current_module = current_module;
86         } else {
87                 func_display = &private_module->func_display;
88                 if (!func_display->display_handle_events)
89                         return TDM_ERROR_NONE;
90
91                 private_display = private_module->private_display;
92                 private_display->current_module = private_module;
93                 ret = func_display->display_handle_events(private_module->bdata);
94                 private_display->current_module = NULL;
95         }
96
97         return ret;
98 }
99
100 INTERN tdm_error
101 tdm_event_loop_init(tdm_private_display *private_display)
102 {
103         tdm_private_loop *private_loop;
104         tdm_error ret;
105
106         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
107
108         if (private_display->private_loop)
109                 return TDM_ERROR_NONE;
110
111         private_loop = calloc(1, sizeof * private_loop);
112         if (!private_loop) {
113                 TDM_ERR("alloc failed");
114                 return TDM_ERROR_OUT_OF_MEMORY;
115         }
116
117         private_loop->wl_display = wl_display_create();
118         if (!private_loop->wl_display) {
119                 TDM_ERR("creating a wayland display failed");
120                 free(private_loop);
121                 return TDM_ERROR_OUT_OF_MEMORY;
122         }
123         private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display);
124
125         ret = tdm_server_init(private_loop);
126         if (ret != TDM_ERROR_NONE) {
127                 TDM_ERR("server init failed");
128                 wl_display_destroy(private_loop->wl_display);
129                 free(private_loop);
130                 return TDM_ERROR_OPERATION_FAILED;
131         }
132
133         LIST_INITHEAD(&private_loop->source_list);
134
135         private_loop->dpy = private_display;
136         private_display->private_loop = private_loop;
137
138         ret = tdm_thread_init(private_loop);
139         if (ret != TDM_ERROR_NONE) {
140                 TDM_ERR("thread init failed");
141                 tdm_server_deinit(private_loop);
142                 wl_display_destroy(private_loop->wl_display);
143                 free(private_loop);
144                 return TDM_ERROR_OPERATION_FAILED;
145         }
146
147         keep_private_loop = private_loop;
148
149         TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop));
150
151         return TDM_ERROR_NONE;
152 }
153
154 INTERN void
155 tdm_event_loop_deinit(tdm_private_display *private_display)
156 {
157         tdm_private_module *private_module = NULL;
158         tdm_event_loop_source_base *source = NULL, *ss = NULL;
159
160         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
161
162         if (!private_display->private_loop)
163                 return;
164
165         if (tdm_thread_is_running())
166                 TDM_ERR("thread is still running. tdm_event_loop_stop SHOULD be called");
167
168         tdm_server_deinit(private_display->private_loop);
169
170         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
171                 if (private_module->event_source)
172                         tdm_event_loop_source_remove(private_module->event_source);
173                 private_module->event_source = NULL;
174                 private_module->fd = -1;
175         }
176
177         LIST_FOR_EACH_ENTRY_SAFE(source, ss, &private_display->private_loop->source_list, link) {
178                 tdm_event_loop_source_remove(source);
179         }
180
181 #if WAYLAND_VERSION_MAJOR >= 1 && WAYLAND_VERSION_MINOR >= 15
182         wl_display_destroy_clients(private_display->private_loop->wl_display);
183 #endif
184
185         wl_display_destroy(private_display->private_loop->wl_display);
186
187         free(private_display->private_loop);
188         private_display->private_loop = NULL;
189         keep_private_loop = NULL;
190
191         TDM_INFO("event loop deinit done");
192 }
193
194 INTERN void
195 tdm_event_loop_stop(tdm_private_display *private_display)
196 {
197         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
198
199         /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
200         tdm_thread_deinit(private_display->private_loop);
201 }
202
203 INTERN void
204 tdm_event_loop_create_backend_source(tdm_private_display *private_display)
205 {
206         tdm_private_loop *private_loop = private_display->private_loop;
207         tdm_private_module *private_module = NULL;
208         tdm_error ret;
209         int fd = -1;
210
211         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
212         TDM_RETURN_IF_FAIL(private_loop != NULL);
213
214         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
215                 if (private_module->use_hal_tdm) {
216                         if (hal_tdm_display_get_fd(private_module->htdm_dpy, &fd) != HAL_TDM_ERROR_NONE) {
217                                 TDM_INFO("TDM backend module won't offer a display fd");
218                                 private_module->event_source = NULL;
219                                 private_module->fd = -1;
220                                 continue;
221                         }
222                         ret = TDM_ERROR_NONE;
223                 } else {
224                         tdm_func_display *func_display = &private_module->func_display;
225
226                         if (!func_display->display_get_fd) {
227                                 TDM_INFO("TDM backend module won't offer a display fd");
228                                 private_module->event_source = NULL;
229                                 private_module->fd = -1;
230                                 continue;
231                         }
232
233                         ret = func_display->display_get_fd(private_module->bdata, &fd);
234                         assert(func_display->display_handle_events);
235                 }
236                 assert(ret == TDM_ERROR_NONE && fd >= 0);
237
238                 private_module->event_source =
239                         tdm_event_loop_add_fd_handler(private_display, fd,
240                                                                                   TDM_EVENT_LOOP_READABLE,
241                                                                                   _tdm_event_loop_main_fd_handler,
242                                                                                   private_module, &ret);
243                 if (!private_module->event_source) {
244                         TDM_ERR("no backend fd(%d) source", fd);
245                         return;
246                 }
247
248                 private_module->fd = fd;
249
250                 TDM_INFO("backend fd(%d) source created", private_module->fd);
251         }
252 }
253
254 INTERN int
255 tdm_event_loop_get_fd(tdm_private_display *private_display)
256 {
257         tdm_private_loop *private_loop = private_display->private_loop;
258
259         /* DON'T check TDM_MUTEX_IS_LOCKED here */
260
261         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, -1);
262
263         return wl_event_loop_get_fd(private_loop->wl_loop);
264 }
265
266 INTERN tdm_error
267 tdm_event_loop_dispatch(tdm_private_display *private_display)
268 {
269         tdm_private_loop *private_loop = private_display->private_loop;
270
271         /* DON'T check TDM_MUTEX_IS_LOCKED here */
272
273         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_loop != NULL, TDM_ERROR_OPERATION_FAILED);
274
275         if (tdm_debug_module & TDM_DEBUG_EVENT)
276                 TDM_INFO("dispatch");
277
278         if (tdm_thread_is_running() &&
279                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
280                 TDM_NEVER_GET_HERE();
281                 return TDM_ERROR_OPERATION_FAILED;
282         }
283
284         /* Don't set timeout to -1. It can make deadblock by two mutex locks.
285          * If need to set -1, use poll() and call tdm_event_loop_dispatch() after
286          * escaping polling.
287          */
288         if (wl_event_loop_dispatch(private_loop->wl_loop, 0) < 0)
289                 TDM_ERR("dispatch failed");
290
291         wl_display_flush_clients(private_loop->wl_display);
292
293         return TDM_ERROR_NONE;
294 }
295
296
297 INTERN void
298 tdm_event_loop_flush(tdm_private_display *private_display)
299 {
300         tdm_private_loop *private_loop = private_display->private_loop;
301
302         /* DON'T check TDM_MUTEX_IS_LOCKED here */
303
304         TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL);
305
306         if (tdm_thread_is_running() &&
307                 tdm_thread_in_display_thread(syscall(SYS_gettid))) {
308                 TDM_NEVER_GET_HERE();
309                 return;
310         }
311
312         wl_display_flush_clients(private_loop->wl_display);
313 }
314
315 static int
316 _tdm_event_loop_fd_func(int fd, uint32_t wl_mask, void *data)
317 {
318         tdm_event_loop_source_fd *fd_source = (tdm_event_loop_source_fd*)data;
319         tdm_private_display *private_display;
320         tdm_event_loop_mask mask = 0;
321
322         /* DON'T check TDM_MUTEX_IS_LOCKED here */
323
324         TDM_RETURN_VAL_IF_FAIL(fd_source, 1);
325         TDM_RETURN_VAL_IF_FAIL(fd_source->func, 1);
326
327         private_display = fd_source->base.private_display;
328
329         if (wl_mask & WL_EVENT_READABLE)
330                 mask |= TDM_EVENT_LOOP_READABLE;
331         if (wl_mask & WL_EVENT_WRITABLE)
332                 mask |= TDM_EVENT_LOOP_WRITABLE;
333         if (wl_mask & WL_EVENT_HANGUP)
334                 mask |= TDM_EVENT_LOOP_HANGUP;
335         if (wl_mask & WL_EVENT_ERROR)
336                 mask |= TDM_EVENT_LOOP_ERROR;
337
338         _pthread_mutex_lock(&private_display->lock);
339         fd_source->func(fd, mask, fd_source->user_data);
340         _pthread_mutex_unlock(&private_display->lock);
341
342         return 1;
343 }
344
345 EXTERN tdm_event_loop_source *
346 tdm_event_loop_add_fd_handler(tdm_display *dpy, int fd, tdm_event_loop_mask mask,
347                                                           tdm_event_loop_fd_handler func, void *user_data,
348                                                           tdm_error *error)
349 {
350         tdm_private_display *private_display;
351         tdm_private_loop *private_loop;
352         tdm_event_loop_source_fd *fd_source;
353         uint32_t wl_mask = 0;
354         tdm_error ret;
355
356         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
357         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
358         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd >= 0, TDM_ERROR_INVALID_PARAMETER, NULL);
359         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
360
361         private_display = (tdm_private_display*)dpy;
362         private_loop = private_display->private_loop;
363         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
364         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
365
366         fd_source = calloc(1, sizeof(tdm_event_loop_source_fd));
367         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(fd_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
368
369         if (mask & TDM_EVENT_LOOP_READABLE)
370                 wl_mask |= WL_EVENT_READABLE;
371         if (mask & TDM_EVENT_LOOP_WRITABLE)
372                 wl_mask |= WL_EVENT_WRITABLE;
373
374         fd_source->func = func;
375         fd_source->user_data = user_data;
376
377         fd_source->base.private_display = private_display;
378         fd_source->base.wl_source =
379                 wl_event_loop_add_fd(private_loop->wl_loop,
380                                                          fd, wl_mask, _tdm_event_loop_fd_func, fd_source);
381         if (!fd_source->base.wl_source) {
382                 if (error)
383                         *error = TDM_ERROR_OUT_OF_MEMORY;
384                 free(fd_source);
385                 return NULL;
386         }
387
388         LIST_ADDTAIL(&fd_source->base.link, &private_loop->source_list);
389
390         if (error)
391                 *error = TDM_ERROR_NONE;
392
393         return (tdm_event_loop_source *)fd_source;
394 }
395
396 EXTERN tdm_error
397 tdm_event_loop_source_fd_update(tdm_event_loop_source *source, tdm_event_loop_mask mask)
398 {
399         tdm_event_loop_source_fd *fd_source = source;
400         uint32_t wl_mask = 0;
401
402         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
403         TDM_RETURN_VAL_IF_FAIL(fd_source, TDM_ERROR_INVALID_PARAMETER);
404
405         if (mask & TDM_EVENT_LOOP_READABLE)
406                 wl_mask |= WL_EVENT_READABLE;
407         if (mask & TDM_EVENT_LOOP_WRITABLE)
408                 wl_mask |= WL_EVENT_WRITABLE;
409
410         if (wl_event_source_fd_update(fd_source->base.wl_source, wl_mask) < 0) {
411                 TDM_ERR("source update failed: %m");
412                 return TDM_ERROR_OPERATION_FAILED;
413         }
414
415         return TDM_ERROR_NONE;
416 }
417
418 static int
419 _tdm_event_loop_timer_func(void *data)
420 {
421         tdm_event_loop_source_timer *timer_source = (tdm_event_loop_source_timer*)data;
422         tdm_private_display *private_display;
423
424         /* DON'T check TDM_MUTEX_IS_LOCKED here */
425
426         TDM_RETURN_VAL_IF_FAIL(timer_source, 1);
427         TDM_RETURN_VAL_IF_FAIL(timer_source->func, 1);
428
429         private_display = timer_source->base.private_display;
430
431         /* TDM event_loop function is actually for TDM backend module. When we call the
432          * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
433          * mutex things.
434          */
435         _pthread_mutex_lock(&private_display->lock);
436         timer_source->func(timer_source->user_data);
437         _pthread_mutex_unlock(&private_display->lock);
438
439         return 1;
440 }
441
442 EXTERN tdm_event_loop_source *
443 tdm_event_loop_add_timer_handler(tdm_display *dpy, tdm_event_loop_timer_handler func,
444                                                                  void *user_data, tdm_error *error)
445 {
446         tdm_private_display *private_display;
447         tdm_private_loop *private_loop;
448         tdm_event_loop_source_timer *timer_source;
449         tdm_error ret;
450
451         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED, NULL);
452         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy, TDM_ERROR_INVALID_PARAMETER, NULL);
453         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(func, TDM_ERROR_INVALID_PARAMETER, NULL);
454
455         private_display = (tdm_private_display*)dpy;
456         private_loop = private_display->private_loop;
457         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
458         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_loop->wl_loop, TDM_ERROR_INVALID_PARAMETER, NULL);
459
460         timer_source = calloc(1, sizeof(tdm_event_loop_source_timer));
461         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(timer_source, TDM_ERROR_OUT_OF_MEMORY, NULL);
462
463         timer_source->func = func;
464         timer_source->user_data = user_data;
465
466         timer_source->base.private_display = private_display;
467         timer_source->base.wl_source =
468                 wl_event_loop_add_timer(private_loop->wl_loop,
469                                                                 _tdm_event_loop_timer_func, timer_source);
470         if (!timer_source->base.wl_source) {
471                 if (error)
472                         *error = TDM_ERROR_OUT_OF_MEMORY;
473                 free(timer_source);
474                 return NULL;
475         }
476
477         LIST_ADDTAIL(&timer_source->base.link, &private_loop->source_list);
478
479         if (error)
480                 *error = TDM_ERROR_NONE;
481
482         return (tdm_event_loop_source *)timer_source;
483 }
484
485 EXTERN tdm_error
486 tdm_event_loop_source_timer_update(tdm_event_loop_source *source, unsigned int ms_delay)
487 {
488         tdm_event_loop_source_timer *timer_source = source;
489
490         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
491         TDM_RETURN_VAL_IF_FAIL(timer_source, TDM_ERROR_INVALID_PARAMETER);
492
493         if (wl_event_source_timer_update(timer_source->base.wl_source, ms_delay) < 0) {
494                 TDM_ERR("source update failed: %m");
495                 return TDM_ERROR_OPERATION_FAILED;
496         }
497
498         return TDM_ERROR_NONE;
499 }
500
501 EXTERN void
502 tdm_event_loop_source_remove(tdm_event_loop_source *source)
503 {
504         tdm_event_loop_source_base *base = (tdm_event_loop_source_base*)source;
505
506         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
507
508         if (!base || !keep_private_loop)
509                 return;
510
511         LIST_DEL(&base->link);
512
513         wl_event_source_remove(base->wl_source);
514
515         free(source);
516 }
517
518 /* LCOV_EXCL_START */
519 static void
520 _trace_cb_client_destroy(struct wl_listener *listener, void *data)
521 {
522         struct wl_client *client = (struct wl_client *) data;
523         struct timespec tp;
524         unsigned int time;
525         pid_t pid = -1;
526         const char *proc_name;
527         char temp[512] = { 0, }, *p = temp;
528         int len = sizeof(temp), *l = &len;
529
530         wl_client_get_credentials(client, &pid, NULL, NULL);
531         proc_name = tdm_server_get_client_name(pid);
532
533         clock_gettime(CLOCK_MONOTONIC, &tp);
534         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
535
536         TDM_SNPRINTF(p, l, "[%10.3f] Server           [PID:%d] client destroying", time / 1000.0, pid);
537         TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
538
539         TDM_INFO("%s", temp);
540
541         wl_list_remove(&listener->link);
542         free(listener);
543 }
544
545 static void
546 _trace_reg_client_destroy_listener(struct wl_client *client)
547 {
548         struct wl_listener *listener;
549
550         listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
551         if (listener)
552                 return;
553
554         listener = calloc(1, sizeof(struct wl_listener));
555         TDM_RETURN_IF_FAIL(listener != NULL);
556
557         listener->notify = _trace_cb_client_destroy;
558         wl_client_add_destroy_listener(client, listener);
559 }
560
561 static const char *
562 _trace_get_next_argument(const char *signature,
563                                                  struct argument_details *details)
564 {
565         details->nullable = 0;
566         for (; *signature; ++signature) {
567                 switch (*signature) {
568                 case 'i':
569                 case 'u':
570                 case 'f':
571                 case 's':
572                 case 'o':
573                 case 'n':
574                 case 'a':
575                 case 'h':
576                         details->type = *signature;
577                         return signature + 1;
578                 case '?':
579                         details->nullable = 1;
580                         break;
581                 default:
582                         return NULL;
583                 }
584         }
585         details->type = '\0';
586         return signature;
587 }
588
589 static struct wl_protocol_logger *_trace_protocol_logger;
590
591 static void
592 _trace_protocol_logger_cb(void *user_data,
593                                                   enum wl_protocol_logger_type direction,
594                                                   const struct wl_protocol_logger_message *message)
595 {
596         int i;
597         struct argument_details arg;
598         struct wl_client *client = wl_resource_get_client(message->resource);
599         const char *signature = message->message->signature;
600         struct timespec tp;
601         unsigned int time;
602         pid_t pid = -1;
603         const char *proc_name;
604         char temp[512] = { 0, }, *p = temp;
605         int len = sizeof(temp), *l = &len;
606         int send;
607
608         if (client) {
609                 _trace_reg_client_destroy_listener(client);
610                 wl_client_get_credentials(client, &pid, NULL, NULL);
611         }
612
613         proc_name = tdm_server_get_client_name(pid);
614
615         clock_gettime(CLOCK_MONOTONIC, &tp);
616         time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
617
618         send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
619
620         TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
621                                  time / 1000.0,
622                                  send ? "Server -> Client [PID:" : "Server <- Client [PID:",
623                                  pid, "] ",
624                                  wl_resource_get_class(message->resource),
625                                  wl_resource_get_id(message->resource),
626                                  message->message->name);
627
628         for (i = 0; i < message->arguments_count; i++) {
629                 signature = _trace_get_next_argument(signature, &arg);
630                 TDM_RETURN_IF_FAIL(signature != NULL);
631
632                 if (i > 0)
633                         TDM_SNPRINTF(p, l, ", ");
634
635                 switch (arg.type) {
636                 case 'u':
637                         TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
638                         break;
639                 case 'i':
640                         TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
641                         break;
642                 case 'f':
643                         TDM_SNPRINTF(p, l, "%f",
644                                                  wl_fixed_to_double(message->arguments[i].f));
645                         break;
646                 case 's':
647                         TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
648                         break;
649                 case 'o':
650                         if (message->arguments[i].o)
651                                 TDM_SNPRINTF(p, l, "%s@%u",
652                                                          wl_resource_get_class((struct wl_resource *) message->arguments[i].o),
653                                                          wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
654                         else
655                                 TDM_SNPRINTF(p, l, "nil");
656                         break;
657                 case 'n':
658                         TDM_SNPRINTF(p, l, "new id %s@",
659                                                  (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
660                         if (message->arguments[i].n != 0)
661                                 TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
662                         else
663                                 TDM_SNPRINTF(p, l, "nil");
664                         break;
665                 case 'a':
666                         TDM_SNPRINTF(p, l, "array");
667                         break;
668                 case 'h':
669                         TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
670                         break;
671                 default:
672                         return;
673                 }
674         }
675
676         TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
677
678         TDM_INFO("%s", temp);
679 }
680
681 INTERN tdm_error
682 tdm_event_loop_trace_enable(tdm_private_display * private_display,
683                                                         unsigned int enable)
684 {
685         tdm_private_loop *private_loop = private_display->private_loop;
686
687         TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
688
689         if (!enable) {
690                 if (_trace_protocol_logger) {
691                         wl_protocol_logger_destroy(_trace_protocol_logger);
692                         _trace_protocol_logger = NULL;
693                 }
694                 return TDM_ERROR_NONE;
695         }
696
697         if (_trace_protocol_logger)
698                 wl_protocol_logger_destroy(_trace_protocol_logger);
699
700         _trace_protocol_logger =
701                 wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
702
703         return TDM_ERROR_NONE;
704 }
705 /* LCOV_EXCL_STOP */