free(source);
}
+
+static void
+_trace_cb_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct wl_client *client = (struct wl_client *) data;
+ struct timespec tp;
+ unsigned int time;
+ pid_t pid = -1;
+ const char *proc_name;
+ char temp[512] = { 0, }, *p = temp;
+ int len = sizeof(temp), *l = &len;
+
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ proc_name = tdm_server_get_client_name(pid);
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ TDM_SNPRINTF(p, l, "[%10.3f] Server [PID:%d] client destroying", time / 1000.0, pid);
+ TDM_SNPRINTF(p, l, ", cmd: %s", proc_name ? proc_name : "Unknown");
+
+ TDM_INFO("%s", temp);
+
+ wl_list_remove(&listener->link);
+ free(listener);
+}
+
+static void
+_trace_reg_client_destroy_listener(struct wl_client *client)
+{
+ struct wl_listener *listener;
+
+ listener = wl_client_get_destroy_listener(client, _trace_cb_client_destroy);
+ if (listener)
+ return;
+
+ listener = calloc(1, sizeof(struct wl_listener));
+ TDM_RETURN_IF_FAIL(listener != NULL);
+
+ listener->notify = _trace_cb_client_destroy;
+ wl_client_add_destroy_listener(client, listener);
+}
+
+static const char *
+_trace_get_next_argument(const char *signature,
+ struct argument_details *details)
+{
+ details->nullable = 0;
+ for (; *signature; ++signature) {
+ switch (*signature) {
+ case 'i':
+ case 'u':
+ case 'f':
+ case 's':
+ case 'o':
+ case 'n':
+ case 'a':
+ case 'h':
+ details->type = *signature;
+ return signature + 1;
+ case '?':
+ details->nullable = 1;
+ break;
+ default:
+ return NULL;
+ }
+ }
+ details->type = '\0';
+ return signature;
+}
+
+#if !TDM_WAYLAND_LOGGER
+
+static void
+_trace_protocol_cb(struct wl_closure *closure, struct wl_resource *resource, int send)
+{
+ int i;
+ struct argument_details arg;
+ struct wl_object *object = &resource->object;
+ struct wl_client *client = resource->client;
+ const char *signature = closure->message->signature;
+ struct timespec tp;
+ unsigned int time;
+ pid_t pid = -1;
+ const char *proc_name;
+ char temp[512] = { 0, }, *p = temp;
+ int len = sizeof(temp), *l = &len;
+
+ if (client) {
+ _trace_reg_client_destroy_listener(client);
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ }
+
+ proc_name = tdm_server_get_client_name(pid);
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
+ time / 1000.0,
+ send ? "Server -> Client [PID:" : "Server <- Client [PID:",
+ pid, "] ",
+ object->interface->name, object->id, closure->message->name);
+
+ for (i = 0; i < closure->count; i++) {
+ signature = _trace_get_next_argument(signature, &arg);
+ TDM_RETURN_IF_FAIL(signature != NULL);
+
+ if (i > 0)
+ TDM_SNPRINTF(p, l, ", ");
+
+ switch (arg.type) {
+ case 'u':
+ TDM_SNPRINTF(p, l, "%u", closure->args[i].u);
+ break;
+ case 'i':
+ TDM_SNPRINTF(p, l, "%d", closure->args[i].i);
+ break;
+ case 'f':
+ TDM_SNPRINTF(p, l, "%f", wl_fixed_to_double(closure->args[i].f));
+ break;
+ case 's':
+ TDM_SNPRINTF(p, l, "\"%s\"", closure->args[i].s);
+ break;
+ case 'o':
+ if (closure->args[i].o)
+ TDM_SNPRINTF(p, l, "%s@%u", closure->args[i].o->interface->name, closure->args[i].o->id);
+ else
+ TDM_SNPRINTF(p, l, "nil");
+ break;
+ case 'n':
+ TDM_SNPRINTF(p, l, "new id %s@",
+ (closure->message->types[i]) ? closure->message->types[i]->name : "[unknown]");
+ if (closure->args[i].n != 0)
+ TDM_SNPRINTF(p, l, "%u", closure->args[i].n);
+ else
+ TDM_SNPRINTF(p, l, "nil");
+ break;
+ case 'a':
+ TDM_SNPRINTF(p, l, "array");
+ break;
+ case 'h':
+ TDM_SNPRINTF(p, l, "fd %d", closure->args[i].h);
+ break;
+ default:
+ return;
+ }
+ }
+
+ TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
+
+ TDM_INFO("%s", temp);
+}
+
+#else
+
+static struct wl_protocol_logger *_trace_protocol_logger;
+
+static void
+_trace_protocol_logger_cb(void *user_data,
+ enum wl_protocol_logger_type direction,
+ const struct wl_protocol_logger_message *message)
+{
+ int i;
+ struct argument_details arg;
+ struct wl_client *client = wl_resource_get_client(message->resource);
+ const char *signature = message->message->signature;
+ struct timespec tp;
+ unsigned int time;
+ pid_t pid = -1;
+ const char *proc_name;
+ char temp[512] = { 0, }, *p = temp;
+ int len = sizeof(temp), *l = &len;
+ int send;
+
+ if (client) {
+ _trace_reg_client_destroy_listener(client);
+ wl_client_get_credentials(client, &pid, NULL, NULL);
+ }
+
+ proc_name = tdm_server_get_client_name(pid);
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ send = (direction == WL_PROTOCOL_LOGGER_EVENT) ? 1 : 0;
+
+ TDM_SNPRINTF(p, l, "[%10.3f] %s%d%s%s@%u.%s(",
+ time / 1000.0,
+ send ? "Server -> Client [PID:" : "Server <- Client [PID:",
+ pid, "] ",
+ wl_resource_get_name(message->resource),
+ wl_resource_get_id(message->resource),
+ message->message->name);
+
+ for (i = 0; i < message->arguments_count; i++) {
+ signature = _trace_get_next_argument(signature, &arg);
+ TDM_RETURN_IF_FAIL(signature != NULL);
+
+ if (i > 0)
+ TDM_SNPRINTF(p, l, ", ");
+
+ switch (arg.type) {
+ case 'u':
+ TDM_SNPRINTF(p, l, "%u", message->arguments[i].u);
+ break;
+ case 'i':
+ TDM_SNPRINTF(p, l, "%d", message->arguments[i].i);
+ break;
+ case 'f':
+ TDM_SNPRINTF(p, l, "%f",
+ wl_fixed_to_double(message->arguments[i].f));
+ break;
+ case 's':
+ TDM_SNPRINTF(p, l, "\"%s\"", message->arguments[i].s);
+ break;
+ case 'o':
+ if (message->arguments[i].o)
+ TDM_SNPRINTF(p, l, "%s@%u",
+ wl_resource_get_name((struct wl_resource *) message->arguments[i].o),
+ wl_resource_get_id((struct wl_resource *) message->arguments[i].o));
+ else
+ TDM_SNPRINTF(p, l, "nil");
+ break;
+ case 'n':
+ TDM_SNPRINTF(p, l, "new id %s@",
+ (message->message->types[i]) ? message->message->types[i]->name : "[unknown]");
+ if (message->arguments[i].n != 0)
+ TDM_SNPRINTF(p, l, "%u", message->arguments[i].n);
+ else
+ TDM_SNPRINTF(p, l, "nil");
+ break;
+ case 'a':
+ TDM_SNPRINTF(p, l, "array");
+ break;
+ case 'h':
+ TDM_SNPRINTF(p, l, "fd %d", message->arguments[i].h);
+ break;
+ default:
+ return;
+ }
+ }
+
+ TDM_SNPRINTF(p, l, "), cmd: %s", proc_name ? proc_name : "Unknown");
+
+ TDM_INFO("%s", temp);
+}
+#endif
+
+INTERN tdm_error
+tdm_event_loop_trace_enable(tdm_private_display * private_display,
+ unsigned int enable)
+{
+ tdm_private_loop *private_loop = private_display->private_loop;
+
+ TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_NONE);
+
+ if (!enable) {
+#if !TDM_WAYLAND_LOGGER
+ wl_debug_server_debug_func_set(NULL);
+#else
+ if (_trace_protocol_logger) {
+ wl_protocol_logger_destroy(_trace_protocol_logger);
+ _trace_protocol_logger = NULL;
+ }
+#endif
+ return TDM_ERROR_NONE;
+ }
+
+#if !TDM_WAYLAND_LOGGER
+ wl_debug_server_debug_func_set((wl_server_debug_func_ptr) _trace_protocol_cb);
+#else
+ if (_trace_protocol_logger)
+ wl_protocol_logger_destroy(_trace_protocol_logger);
+
+ _trace_protocol_logger =
+ wl_display_add_protocol_logger(private_loop->wl_display, _trace_protocol_logger_cb, NULL);
+#endif
+
+ return TDM_ERROR_NONE;
+}