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