#include <time.h>
#include <assert.h>
-#include "timeline.h"
#include <libweston/libweston.h>
+#include <libweston/weston-log.h>
+#include "timeline.h"
+#include "weston-log-internal.h"
WL_EXPORT int weston_timeline_enabled_;
struct timeline_emit_context {
FILE *cur;
- FILE *out;
- unsigned series;
+ struct weston_log_subscription *subscription;
};
-static unsigned
-timeline_new_id(void)
+/** Create a timeline subscription and hang it off the subscription
+ *
+ * Called when the subscription is created.
+ *
+ * @ingroup internal-log
+ */
+void
+weston_timeline_create_subscription(struct weston_log_subscription *sub,
+ void *user_data)
{
- static unsigned idc;
+ struct weston_timeline_subscription *tl_sub = zalloc(sizeof(*tl_sub));
+ if (!tl_sub)
+ return;
- if (++idc == 0)
- ++idc;
+ wl_list_init(&tl_sub->objects);
- return idc;
+ /* attach this timeline_subscription to it */
+ weston_log_subscription_set_data(sub, tl_sub);
}
-static int
-check_series(struct timeline_emit_context *ctx,
- struct weston_timeline_object *to)
+static void
+weston_timeline_destroy_subscription_object(struct weston_timeline_subscription_object *sub_obj)
+{
+ /* remove the notify listener */
+ wl_list_remove(&sub_obj->destroy_listener.link);
+ sub_obj->destroy_listener.notify = NULL;
+
+ wl_list_remove(&sub_obj->subscription_link);
+ free(sub_obj);
+}
+
+/** Destroy the timeline subscription and all timeline subscription objects
+ * associated with it.
+ *
+ * Called when (before) the subscription is destroyed.
+ *
+ * @ingroup internal-log
+ */
+void
+weston_timeline_destroy_subscription(struct weston_log_subscription *sub,
+ void *user_data)
{
- if (to->series == 0 || to->series != ctx->series) {
- to->series = ctx->series;
- to->id = timeline_new_id();
- return 1;
+ struct weston_timeline_subscription *tl_sub =
+ weston_log_subscription_get_data(sub);
+ struct weston_timeline_subscription_object *sub_obj, *tmp_sub_obj;
+
+ if (!tl_sub)
+ return;
+
+ wl_list_for_each_safe(sub_obj, tmp_sub_obj,
+ &tl_sub->objects, subscription_link)
+ weston_timeline_destroy_subscription_object(sub_obj);
+
+ free(tl_sub);
+}
+
+static bool
+weston_timeline_check_object_refresh(struct weston_timeline_subscription_object *obj)
+{
+ if (obj->force_refresh == true) {
+ obj->force_refresh = false;
+ return true;
}
+ return false;
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_search(struct weston_timeline_subscription *tl_sub,
+ void *object)
+{
+ struct weston_timeline_subscription_object *sub_obj;
+
+ wl_list_for_each(sub_obj, &tl_sub->objects, subscription_link)
+ if (sub_obj->object == object)
+ return sub_obj;
+
+ return NULL;
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_object_create(void *object,
+ struct weston_timeline_subscription *tm_sub)
+{
+ struct weston_timeline_subscription_object *sub_obj;
- if (to->force_refresh) {
- to->force_refresh = 0;
- return 1;
+ sub_obj = zalloc(sizeof(*sub_obj));
+ sub_obj->id = ++tm_sub->next_id;
+ sub_obj->object = object;
+
+ /* when the object is created so that it has the chance to display the
+ * object ID, we set the refresh status; it will only be re-freshed by
+ * the backend (or part parts) when the underlying objects has suffered
+ * modifications */
+ sub_obj->force_refresh = true;
+
+ wl_list_insert(&tm_sub->objects, &sub_obj->subscription_link);
+
+ return sub_obj;
+}
+
+static void
+weston_timeline_destroy_subscription_object_notify(struct wl_listener *listener, void *data)
+{
+ struct weston_timeline_subscription_object *sub_obj;
+
+ sub_obj = wl_container_of(listener, sub_obj, destroy_listener);
+ weston_timeline_destroy_subscription_object(sub_obj);
+}
+
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_output_ensure(struct weston_timeline_subscription *tl_sub,
+ struct weston_output *output)
+{
+ struct weston_timeline_subscription_object *sub_obj;
+
+ sub_obj = weston_timeline_subscription_search(tl_sub, output);
+ if (!sub_obj) {
+ sub_obj = weston_timeline_subscription_object_create(output, tl_sub);
+
+ sub_obj->destroy_listener.notify =
+ weston_timeline_destroy_subscription_object_notify;
+ wl_signal_add(&output->destroy_signal,
+ &sub_obj->destroy_listener);
}
+ return sub_obj;
+}
- return 0;
+static struct weston_timeline_subscription_object *
+weston_timeline_subscription_surface_ensure(struct weston_timeline_subscription *tl_sub,
+ struct weston_surface *surface)
+{
+ struct weston_timeline_subscription_object *sub_obj;
+
+ sub_obj = weston_timeline_subscription_search(tl_sub, surface);
+ if (!sub_obj) {
+ sub_obj = weston_timeline_subscription_object_create(surface, tl_sub);
+
+ sub_obj->destroy_listener.notify =
+ weston_timeline_destroy_subscription_object_notify;
+ wl_signal_add(&surface->destroy_signal,
+ &sub_obj->destroy_listener);
+ }
+
+ return sub_obj;
}
static void
-fprint_quoted_string(FILE *fp, const char *str)
+fprint_quoted_string(struct weston_log_subscription *sub, const char *str)
{
if (!str) {
- fprintf(fp, "null");
+ weston_log_subscription_printf(sub, "null");
return;
}
- fprintf(fp, "\"%s\"", str);
+ weston_log_subscription_printf(sub, "\"%s\"", str);
+}
+
+static void
+emit_weston_output_print_id(struct weston_log_subscription *sub,
+ struct weston_timeline_subscription_object *sub_obj,
+ const char *name)
+{
+ if (!weston_timeline_check_object_refresh(sub_obj))
+ return;
+
+ weston_log_subscription_printf(sub, "{ \"id\":%u, "
+ "\"type\":\"weston_output\", \"name\":", sub_obj->id);
+ fprint_quoted_string(sub, name);
+ weston_log_subscription_printf(sub, " }\n");
}
static int
emit_weston_output(struct timeline_emit_context *ctx, void *obj)
{
- struct weston_output *o = obj;
+ struct weston_log_subscription *sub = ctx->subscription;
+ struct weston_output *output = obj;
+ struct weston_timeline_subscription_object *sub_obj;
+ struct weston_timeline_subscription *tl_sub;
- if (check_series(ctx, &o->timeline)) {
- fprintf(ctx->out, "{ \"id\":%u, "
- "\"type\":\"weston_output\", \"name\":",
- o->timeline.id);
- fprint_quoted_string(ctx->out, o->name);
- fprintf(ctx->out, " }\n");
- }
+ tl_sub = weston_log_subscription_get_data(sub);
+ sub_obj = weston_timeline_subscription_output_ensure(tl_sub, output);
+ emit_weston_output_print_id(sub, sub_obj, output->name);
- fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
+ assert(sub_obj->id != 0);
+ fprintf(ctx->cur, "\"wo\":%u", sub_obj->id);
return 1;
}
+
static void
-check_weston_surface_description(struct timeline_emit_context *ctx,
- struct weston_surface *s)
+check_weston_surface_description(struct weston_log_subscription *sub,
+ struct weston_surface *s,
+ struct weston_timeline_subscription *tm_sub,
+ struct weston_timeline_subscription_object *sub_obj)
{
struct weston_surface *mains;
char d[512];
char mainstr[32];
- if (!check_series(ctx, &s->timeline))
+ if (!weston_timeline_check_object_refresh(sub_obj))
return;
mains = weston_surface_get_main_surface(s);
if (mains != s) {
- check_weston_surface_description(ctx, mains);
- if (snprintf(mainstr, sizeof(mainstr),
- ", \"main_surface\":%u", mains->timeline.id) < 0)
+ struct weston_timeline_subscription_object *new_sub_obj;
+
+ new_sub_obj = weston_timeline_subscription_surface_ensure(tm_sub, mains);
+ check_weston_surface_description(sub, mains, tm_sub, new_sub_obj);
+ if (snprintf(mainstr, sizeof(mainstr), ", \"main_surface\":%u",
+ new_sub_obj->id) < 0)
mainstr[0] = '\0';
} else {
mainstr[0] = '\0';
if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
d[0] = '\0';
- fprintf(ctx->out, "{ \"id\":%u, "
- "\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
- fprint_quoted_string(ctx->out, d[0] ? d : NULL);
- fprintf(ctx->out, "%s }\n", mainstr);
+ weston_log_subscription_printf(sub, "{ \"id\":%u, "
+ "\"type\":\"weston_surface\", \"desc\":",
+ sub_obj->id);
+ fprint_quoted_string(sub, d[0] ? d : NULL);
+ weston_log_subscription_printf(sub, "%s }\n", mainstr);
}
static int
emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
{
- struct weston_surface *s = obj;
+ struct weston_log_subscription *sub = ctx->subscription;
+ struct weston_surface *surface = obj;
+ struct weston_timeline_subscription_object *sub_obj;
+ struct weston_timeline_subscription *tl_sub;
+
+ tl_sub = weston_log_subscription_get_data(sub);
+ sub_obj = weston_timeline_subscription_surface_ensure(tl_sub, surface);
+ check_weston_surface_description(sub, surface, tl_sub, sub_obj);
- check_weston_surface_description(ctx, s);
- fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
+ assert(sub_obj->id != 0);
+ fprintf(ctx->cur, "\"ws\":%u", sub_obj->id);
return 1;
}
if (ferror(ctx.cur)) {
weston_log("Timeline error in constructing entry, closing.\n");
} else {
- fprintf(ctx.out, "%s", buf);
+ weston_log_subscription_printf(ctx.subscription, "%s", buf);
}
fclose(ctx.cur);