core: Layer & View implementation
authorTaekyun Kim <tkq.kim@samsung.com>
Tue, 12 May 2015 04:37:24 +0000 (13:37 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Fri, 19 Jun 2015 09:06:40 +0000 (18:06 +0900)
A compositor has layers stacked from bottom to top. Each layer has its views
which are also stached from bottom to top. Layer can be used for grouping views
and maintaining z-order. For example, a desktop can have several layers like
panel, background and application layers.

View represent visible elements in the compositor space.

<< Written under following criteria. >>

1. View is a rectangle of the same size with its surface.

2. A view can have a parent and multiple childs.

3. View position and transform is relative to its parent.

4. Parent-Child relationship does not affect the z-order.

5. A view can be contained in a single layer at a time.

Change-Id: Ib0ad01575467960c5b04d968389e37879500f21b

src/Makefile.am
src/compositor.c
src/layer.c [new file with mode: 0644]
src/pepper-internal.h
src/pepper.h
src/view.c [new file with mode: 0644]

index 4d18e4a..723b1ad 100644 (file)
@@ -23,7 +23,9 @@ libpepper_la_SOURCES = pepper.h                 \
                        buffer.c                 \
                        renderer.c               \
                        pixman-renderer.c        \
-                       data-device.c
+                       data-device.c            \
+                       view.c                   \
+                       layer.c
 
 # gl renderer
 if ENABLE_GL_RENDERER
index bb9554e..594c6bd 100644 (file)
@@ -88,6 +88,7 @@ pepper_compositor_create(const char *socket_name)
         goto error;
     }
 
+    wl_list_init(&compositor->layers);
     return compositor;
 
 error:
diff --git a/src/layer.c b/src/layer.c
new file mode 100644 (file)
index 0000000..e873d68
--- /dev/null
@@ -0,0 +1,152 @@
+#include "pepper-internal.h"
+
+PEPPER_API pepper_layer_t *
+pepper_layer_create(pepper_compositor_t *compositor)
+{
+    pepper_layer_t *layer;
+    PEPPER_ASSERT(compositor != NULL);
+
+    layer = pepper_calloc(1, sizeof(pepper_layer_t));
+    if (!layer)
+        return NULL;
+
+    layer->compositor = compositor;
+    wl_list_init(&layer->views);
+
+    return layer;
+}
+
+PEPPER_API pepper_compositor_t *
+pepper_layer_get_compositor(pepper_layer_t *layer)
+{
+    return layer->compositor;
+}
+
+PEPPER_API void
+pepper_compositor_stack_layer(pepper_compositor_t *compositor, pepper_layer_t *layer,
+                              pepper_layer_t *below)
+{
+    PEPPER_ASSERT(compositor != NULL);
+    PEPPER_ASSERT(!below || (layer->compositor == below->compositor));
+
+    if ((!below && (layer->link.prev == &compositor->layers)) ||
+        ( below && (layer->link.prev == &below->link)))
+        return;
+
+    if (!wl_list_empty(&layer->link))
+    {
+        wl_list_remove(&layer->link);
+
+        /* TODO: Handle layer removal. */
+    }
+
+    if (below)
+        wl_list_insert(&below->link, &layer->link);
+    else
+        wl_list_insert(&compositor->layers, &layer->link);
+
+    /* TODO: Handle layer insert. */
+}
+
+PEPPER_API pepper_layer_t *
+pepper_compositor_get_top_layer(pepper_compositor_t *compositor)
+{
+    pepper_layer_t *layer;
+
+    if (wl_list_empty(&compositor->layers))
+        return NULL;
+
+    layer = wl_container_of(compositor->layers.prev, layer, link);
+    return layer;
+}
+
+PEPPER_API pepper_layer_t *
+pepper_compositor_get_bottom_layer(pepper_compositor_t *compositor)
+{
+    pepper_layer_t *layer;
+
+    if (wl_list_empty(&compositor->layers))
+        return NULL;
+
+    layer = wl_container_of(compositor->layers.next, layer, link);
+    return layer;
+}
+
+PEPPER_API pepper_layer_t *
+pepper_layer_get_above(pepper_layer_t *layer)
+{
+    pepper_layer_t *above;
+
+    if (wl_list_empty(&layer->link))
+        return NULL;
+
+    if (layer->link.next == &layer->compositor->layers)
+        return NULL;
+
+    above = wl_container_of(layer->link.next, layer, link);
+    return above;
+}
+
+PEPPER_API pepper_layer_t *
+pepper_layer_get_below(pepper_layer_t *layer)
+{
+    pepper_layer_t *below;
+
+    if (wl_list_empty(&layer->link))
+        return NULL;
+
+    if (layer->link.prev == &layer->compositor->layers)
+        return NULL;
+
+    below = wl_container_of(layer->link.prev, layer, link);
+    return below;
+}
+
+PEPPER_API void
+pepper_layer_stack_view(pepper_layer_t *layer, pepper_view_t *view, pepper_view_t *below)
+{
+    PEPPER_ASSERT(layer != NULL);
+    PEPPER_ASSERT(!below || (below->compositor == view->compositor));
+
+    if ((!below && (view->layer_link.prev == &layer->views)) ||
+        ( below && (view->layer_link.prev == &below->layer_link)))
+        return;
+
+    if (view->layer)
+    {
+        wl_list_remove(&view->layer_link);
+
+        /* TODO: Handle view removal. */
+    }
+
+    if (below)
+        wl_list_insert(&below->layer_link, &view->layer_link);
+    else
+        wl_list_insert(&layer->views, &view->layer_link);
+
+    /* TODO: Handle view insert. */
+}
+
+PEPPER_API pepper_view_t *
+pepper_layer_get_top_view(pepper_layer_t *layer)
+{
+    pepper_view_t *view;
+
+    if (wl_list_empty(&layer->views))
+        return NULL;
+
+    view = wl_container_of(layer->views.prev, view, layer_link);
+    return view;
+}
+
+PEPPER_API pepper_view_t *
+pepper_layer_get_bottom_view(pepper_layer_t *layer)
+{
+    pepper_view_t *view;
+
+    if (wl_list_empty(&layer->views))
+        return NULL;
+
+    view = wl_container_of(layer->views.next, view, layer_link);
+    return view;
+}
index 0ae6414..ae816ad 100644 (file)
@@ -21,6 +21,7 @@ struct pepper_compositor
     struct wl_list      surfaces;
     struct wl_list      regions;
     struct wl_list      seat_list;
+    struct wl_list      layers;
 };
 
 struct pepper_output
@@ -215,4 +216,36 @@ struct pepper_data_device
 pepper_bool_t
 pepper_data_device_manager_init(struct wl_display *display);
 
+struct pepper_view
+{
+    pepper_compositor_t    *compositor;
+    struct wl_signal        destroy_signal;
+
+    pepper_surface_t       *surface;
+    pepper_bool_t           mapped;
+    float                   alpha;
+
+    pepper_view_t          *parent;
+    struct wl_list          parent_link;
+    struct wl_listener      parent_destroy_listener;
+    struct wl_list          childs;
+
+    struct {
+        pepper_bool_t       dirty;
+
+        float               x, y;
+        pepper_matrix_t     transform;
+    } geometry;
+
+    pepper_layer_t         *layer;
+    struct wl_list          layer_link;
+};
+
+struct pepper_layer
+{
+    pepper_compositor_t    *compositor;
+    struct wl_list          link;
+    struct wl_list          views;
+};
+
 #endif /* PEPPER_INTERNAL_H */
index 6652c99..23ec358 100644 (file)
@@ -38,6 +38,10 @@ typedef struct pepper_input_event       pepper_input_event_t;
 
 typedef struct pepper_renderer          pepper_renderer_t;
 typedef struct pepper_surface           pepper_surface_t;
+typedef struct pepper_view              pepper_view_t;
+typedef struct pepper_layer             pepper_layer_t;
+
+typedef struct pepper_matrix            pepper_matrix_t;
 
 #define PEPPER_FORMAT(type, bpp, a, r, g, b)    \
     ((((type) & 0xff) << 24)    |               \
@@ -78,6 +82,55 @@ typedef enum
     PEPPER_FORMAT_ALPHA         = PEPPER_FORMAT(PEPPER_FORMAT_TYPE_ARGB,     8,  8,  0,  0,  0),
 } pepper_format_t;
 
+#define PEPPER_MATRIX_IS_IDENTITY   1
+
+struct pepper_matrix
+{
+    float       m[16];
+    uint32_t    flags;
+};
+
+static inline void
+pepper_matrix_load_identity(pepper_matrix_t *matrix)
+{
+    matrix->m[ 0] = 1.0f;
+    matrix->m[ 1] = 0.0f;
+    matrix->m[ 2] = 0.0f;
+    matrix->m[ 3] = 0.0f;
+
+    matrix->m[ 4] = 0.0f;
+    matrix->m[ 5] = 1.0f;
+    matrix->m[ 6] = 0.0f;
+    matrix->m[ 7] = 0.0f;
+
+    matrix->m[ 8] = 0.0f;
+    matrix->m[ 9] = 0.0f;
+    matrix->m[10] = 1.0f;
+    matrix->m[11] = 0.0f;
+
+    matrix->m[12] = 0.0f;
+    matrix->m[13] = 0.0f;
+    matrix->m[14] = 0.0f;
+    matrix->m[15] = 1.0f;
+
+    matrix->flags = PEPPER_MATRIX_IS_IDENTITY;
+}
+
+static inline pepper_bool_t
+pepper_matrix_equal(const pepper_matrix_t *a, const pepper_matrix_t *b)
+{
+    return a->m[ 0] == b->m[ 0] && a->m[ 1] == b->m[ 1] &&
+           a->m[ 2] == b->m[ 2] && a->m[ 3] && b->m[ 3] &&
+           a->m[ 4] == b->m[ 4] && a->m[ 5] && b->m[ 5] &&
+           a->m[ 6] == b->m[ 6] && a->m[ 7] && b->m[ 7] &&
+           a->m[ 8] == b->m[ 8] && a->m[ 9] && b->m[ 9] &&
+           a->m[10] == b->m[10] && a->m[11] && b->m[11] &&
+           a->m[12] == b->m[12] && a->m[13] && b->m[13] &&
+           a->m[14] == b->m[14] && a->m[15] && b->m[15];
+}
+
+/* TODO: Other matrix utility functions. */
+
 struct pepper_output_geometry
 {
     int32_t     x;
@@ -239,6 +292,93 @@ pepper_surface_get_role(pepper_surface_t *surface);
 PEPPER_API pepper_bool_t
 pepper_surface_set_role(pepper_surface_t *surface, const char *role);
 
+/* View. */
+PEPPER_API pepper_view_t *
+pepper_view_create(pepper_compositor_t *compositor, pepper_surface_t *surface);
+
+PEPPER_API pepper_compositor_t *
+pepper_view_get_compositor(pepper_view_t *view);
+
+PEPPER_API pepper_surface_t *
+pepper_view_get_surface(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_destroy(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_add_destroy_listener(pepper_view_t *view, struct wl_listener *listener);
+
+PEPPER_API void
+pepper_view_set_transform(pepper_view_t *view, const pepper_matrix_t *matrix);
+
+PEPPER_API const pepper_matrix_t *
+pepper_view_get_transform(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_set_position(pepper_view_t *view, float x, float y);
+
+PEPPER_API void
+pepper_view_get_position(pepper_view_t *view, float *x, float *y);
+
+PEPPER_API void
+pepper_view_set_parent(pepper_view_t *view, pepper_view_t *parent);
+
+PEPPER_API pepper_view_t *
+pepper_view_get_parent(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_map(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_unmap(pepper_view_t *view);
+
+PEPPER_API pepper_bool_t
+pepper_view_is_mapped(pepper_view_t *view);
+
+PEPPER_API void
+pepper_view_set_alpha(pepper_view_t *view, float alpha);
+
+PEPPER_API float
+pepper_view_get_alpha(pepper_view_t *view);
+
+PEPPER_API pepper_view_t *
+pepper_view_get_above(pepper_view_t *view);
+
+PEPPER_API pepper_view_t *
+pepper_view_get_below(pepper_view_t *view);
+
+/* Layer. */
+PEPPER_API pepper_layer_t *
+pepper_layer_create(pepper_compositor_t *compositor);
+
+PEPPER_API pepper_compositor_t *
+pepper_layer_get_compositor(pepper_layer_t *layer);
+
+PEPPER_API void
+pepper_compositor_stack_layer(pepper_compositor_t *compositor, pepper_layer_t *layer,
+                              pepper_layer_t *below);
+
+PEPPER_API pepper_layer_t *
+pepper_compositor_get_top_layer(pepper_compositor_t *compositor);
+
+PEPPER_API pepper_layer_t *
+pepper_compositor_get_bottom_layer(pepper_compositor_t *compositor);
+
+PEPPER_API pepper_layer_t *
+pepper_layer_get_above(pepper_layer_t *layer);
+
+PEPPER_API pepper_layer_t *
+pepper_layer_get_below(pepper_layer_t *layer);
+
+PEPPER_API void
+pepper_layer_stack_view(pepper_layer_t *layer, pepper_view_t *view, pepper_view_t *below);
+
+PEPPER_API pepper_view_t *
+pepper_layer_get_top_view(pepper_layer_t *layer);
+
+PEPPER_API pepper_view_t *
+pepper_layer_get_bottom_view(pepper_layer_t *layer);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/view.c b/src/view.c
new file mode 100644 (file)
index 0000000..7fdb01c
--- /dev/null
@@ -0,0 +1,225 @@
+#include "pepper-internal.h"
+#include <string.h>
+
+void
+view_geometry_dirty(pepper_view_t *view)
+{
+    pepper_view_t *child;
+
+    if (view->geometry.dirty)
+        return;
+
+    view->geometry.dirty = PEPPER_TRUE;
+
+    wl_list_for_each(child, &view->childs, parent_link)
+        view_geometry_dirty(child);
+}
+
+static void
+handle_parent_destroy(struct wl_listener *listener, void *data)
+{
+    pepper_view_t *view = wl_container_of(listener, view, parent_destroy_listener);
+
+    PEPPER_ASSERT(view->parent == data);
+    pepper_view_set_parent(view, NULL);
+}
+
+PEPPER_API pepper_view_t *
+pepper_view_create(pepper_compositor_t *compositor, pepper_surface_t *surface)
+{
+    pepper_view_t *view;
+
+    if (!compositor)
+    {
+        PEPPER_ERROR("Compositor must be given.\n");
+        return NULL;
+    }
+
+    if (surface && surface->compositor != compositor)
+    {
+        PEPPER_ERROR("Unable to create a view for a surface from different compositor.\n");
+        return NULL;
+    }
+
+    view = pepper_calloc(1, sizeof(pepper_view_t));
+    if (!view)
+        return NULL;
+
+    view->compositor = compositor;
+    wl_signal_init(&view->destroy_signal);
+
+    view->surface = surface;
+    view->alpha = 1.0f;
+
+    view->parent_destroy_listener.notify = handle_parent_destroy;
+    wl_list_init(&view->childs);
+
+    /* Initialize geometry properties. */
+    view->geometry.dirty = PEPPER_TRUE;
+    view->geometry.x = 0.0f;
+    view->geometry.y = 0.0f;
+    pepper_matrix_load_identity(&view->geometry.transform);
+
+    return view;
+}
+
+PEPPER_API pepper_compositor_t *
+pepper_view_get_compositor(pepper_view_t *view)
+{
+    return view->compositor;
+}
+
+PEPPER_API pepper_surface_t *
+pepper_view_get_surface(pepper_view_t *view)
+{
+    return view->surface;
+}
+
+PEPPER_API void
+pepper_view_destroy(pepper_view_t *view)
+{
+    wl_signal_emit(&view->destroy_signal, view);
+    PEPPER_ASSERT(wl_list_empty(&view->childs));
+
+    if (view->parent)
+    {
+        wl_list_remove(&view->parent_link);
+        wl_list_remove(&view->parent_destroy_listener.link);
+    }
+
+    pepper_free(view);
+}
+
+PEPPER_API void
+pepper_view_add_destroy_listener(pepper_view_t *view, struct wl_listener *listener)
+{
+    wl_signal_add(&view->destroy_signal, listener);
+}
+
+PEPPER_API void
+pepper_view_set_position(pepper_view_t *view, float x, float y)
+{
+    view->geometry.x = x;
+    view->geometry.y = y;
+}
+
+PEPPER_API void
+pepper_view_get_position(pepper_view_t *view, float *x, float *y)
+{
+    if (x)
+        *x = view->geometry.x;
+
+    if (y)
+        *y = view->geometry.y;
+}
+
+PEPPER_API void
+pepper_view_set_transform(pepper_view_t *view, const pepper_matrix_t *matrix)
+{
+    memcpy(&view->geometry.transform, matrix, sizeof(pepper_matrix_t));
+    view_geometry_dirty(view);
+}
+
+PEPPER_API const pepper_matrix_t *
+pepper_view_get_transform(pepper_view_t *view)
+{
+    return &view->geometry.transform;
+}
+
+PEPPER_API void
+pepper_view_set_parent(pepper_view_t *view, pepper_view_t *parent)
+{
+    if (view->parent == parent)
+        return;
+
+    if (view->parent)
+    {
+        wl_list_remove(&view->parent_link);
+        wl_list_remove(&view->parent_destroy_listener.link);
+    }
+
+    view->parent = parent;
+
+    if (parent)
+    {
+        wl_list_insert(&parent->childs, &view->parent_link);
+        pepper_view_add_destroy_listener(parent, &view->parent_destroy_listener);
+    }
+
+    view_geometry_dirty(view);
+}
+
+PEPPER_API pepper_view_t *
+pepper_view_get_parent(pepper_view_t *view)
+{
+    return view->parent;
+}
+
+PEPPER_API void
+pepper_view_map(pepper_view_t *view)
+{
+    if (view->mapped)
+        return;
+
+    view->mapped = PEPPER_TRUE;
+}
+
+PEPPER_API void
+pepper_view_unmap(pepper_view_t *view)
+{
+    if (!view->mapped)
+        return;
+
+    view->mapped = PEPPER_FALSE;
+}
+
+PEPPER_API pepper_bool_t
+pepper_view_is_mapped(pepper_view_t *view)
+{
+    return view->mapped;
+}
+
+PEPPER_API void
+pepper_view_set_alpha(pepper_view_t *view, float alpha)
+{
+    if (view->alpha == alpha)
+        return;
+
+    view->alpha = alpha;
+}
+
+PEPPER_API float
+pepper_view_get_alpha(pepper_view_t *view)
+{
+    return view->alpha;
+}
+
+PEPPER_API pepper_view_t *
+pepper_view_get_above(pepper_view_t *view)
+{
+    pepper_view_t *above;
+
+    if (!view->layer)
+        return NULL;
+
+    if (view->layer_link.next == &view->layer->views)
+        return NULL;
+
+    above = wl_container_of(view->layer_link.next, view, layer_link);
+    return above;
+}
+
+PEPPER_API pepper_view_t *
+pepper_view_get_below(pepper_view_t *view)
+{
+    pepper_view_t *below;
+
+    if (!view->layer)
+        return NULL;
+
+    if (view->layer_link.prev == &view->layer->views)
+        return NULL;
+
+    below = wl_container_of(view->layer_link.prev, view, layer_link);
+    return below;
+}