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