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