pepper: View API refactoring to separate z-order from parent-child relation.
authorTaekyun Kim <tkq.kim@samsung.com>
Mon, 29 Jun 2015 07:31:22 +0000 (16:31 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Tue, 7 Jul 2015 06:56:51 +0000 (15:56 +0900)
Sometimes we want parent-child relationship to affect only transform of the
child not z-order. By separating z-order contraint from parent-child
relationship, we can do much more things with the APIs. For the previous style
stacked views, APIs that are changing z-order now take subtree argument
indicating whether entire subtree movement or just the individual view.

Change-Id: I7c50fae2b8dcabb336571f7dc2b93ca5d161e66c

desktop-shell/src/shell-surface.c
desktop-shell/src/wl-shell.c
pepper/src/compositor.c
pepper/src/output.c
pepper/src/pepper-internal.h
pepper/src/pepper-utils.h
pepper/src/pepper.h
pepper/src/view.c

index 09e8f74..b7464fd 100644 (file)
@@ -92,7 +92,7 @@ shell_surface_create(shell_t *shell, pepper_object_t *surface, struct wl_client
     shsurf->shell   = shell;
     shsurf->client  = client;
     shsurf->surface = surface;
-    shsurf->view    = pepper_compositor_add_view(shell->compositor, NULL, NULL, surface);
+    shsurf->view    = pepper_compositor_add_surface_view(shell->compositor, surface);
     if (!shsurf->view)
     {
         PEPPER_ERROR("pepper_compositor_add_view failed\n");
index f4b80c1..2f03f5b 100644 (file)
@@ -41,7 +41,7 @@ shell_surface_set_toplevel(struct wl_client *client, struct wl_resource *resourc
 
     shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_TOPLEVEL);
 
-    pepper_view_set_visibility(shsurf->view, PEPPER_TRUE);
+    pepper_view_map(shsurf->view);
 }
 
 static void
index b58bedd..30d0fe7 100644 (file)
@@ -76,10 +76,11 @@ pepper_compositor_create(const char *socket_name)
     wl_list_init(&compositor->surfaces);
     wl_list_init(&compositor->seat_list);
     wl_list_init(&compositor->output_list);
-    wl_list_init(&compositor->root_view_list);
-
     wl_list_init(&compositor->event_hook_chain);
 
+    pepper_list_init(&compositor->root_view_list);
+    pepper_list_init(&compositor->view_list);
+
     /* Install default input event handler */
     if( NULL == pepper_compositor_add_event_hook(&compositor->base,
                                                  pepper_compositor_event_handler,
@@ -101,9 +102,6 @@ pepper_compositor_create(const char *socket_name)
         goto error;
     }
 
-    wl_list_init(&compositor->layers);
-    pepper_list_init(&compositor->view_list);
-
     return &compositor->base;
 
 error:
@@ -143,9 +141,7 @@ pepper_compositor_add_damage(pepper_compositor_t *compositor, const pixman_regio
     CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR);
 
     wl_list_for_each(output, &compositor->output_list, link)
-    {
         pepper_output_add_damage(&output->base, region, output->geometry.x, output->geometry.y);
-    }
 }
 
 void
@@ -158,3 +154,14 @@ pepper_compositor_add_damage_rect(pepper_compositor_t *compositor,
     pepper_compositor_add_damage(compositor, &region);
     pixman_region32_fini(&region);
 }
+
+void
+pepper_compositor_schedule_repaint(pepper_compositor_t *compositor)
+{
+    pepper_output_t    *output;
+
+    CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR);
+
+    wl_list_for_each(output, &compositor->output_list, link)
+        pepper_output_schedule_repaint(output);
+}
index 1029245..93cd9c2 100644 (file)
@@ -167,7 +167,7 @@ pepper_output_repaint(pepper_output_t *output)
 {
     PEPPER_ASSERT(!output->frame.pending);
 
-    pepper_compositor_update_view_list(output->compositor);
+    pepper_compositor_update_views(output->compositor);
 
     output->interface->repaint(output->data, &output->compositor->view_list, &output->damage_region);
     output->frame.pending = PEPPER_TRUE;
@@ -356,10 +356,12 @@ pepper_output_add_damage(pepper_object_t *out,
     pixman_region32_intersect_rect(&damage, &damage, 0, 0, output->geometry.w, output->geometry.h);
 
     if (pixman_region32_not_empty(&damage))
+    {
         pixman_region32_union(&output->damage_region, &output->damage_region, &damage);
+        pepper_output_schedule_repaint(output);
+    }
 
     pixman_region32_fini(&damage);
-    pepper_output_schedule_repaint(output);
 }
 
 PEPPER_API void
index 2077c7a..972a6b9 100644 (file)
@@ -88,10 +88,9 @@ struct pepper_compositor
     struct wl_list      surfaces;
     struct wl_list      regions;
     struct wl_list      seat_list;
-    struct wl_list      layers;
     struct wl_list      output_list;
-    struct wl_list      root_view_list;
     struct wl_list      event_hook_chain;
+    pepper_list_t       root_view_list;
     pepper_list_t       view_list;
 };
 
@@ -308,14 +307,14 @@ struct pepper_view
     pepper_object_t         base;
     pepper_compositor_t    *compositor;
 
-    /* Hierarchy. */
+    /* Hierarchy & Z-order. */
     pepper_view_t          *parent;
-    struct wl_list         *container_list;
-    struct wl_list          parent_link;
-    struct wl_list          child_list;
+    pepper_list_t           children_list;
+    pepper_list_t           parent_link;
+    pepper_list_t           z_link;
 
     /* Geometry. */
-    float                   x, y, w, h;
+    double                  x, y, w, h;
     pepper_matrix_t         transform;
     pepper_matrix_t         matrix_to_parent;
     pepper_matrix_t         matrix_to_global;
@@ -324,38 +323,19 @@ struct pepper_view
 
     /* Visibility. */
     pepper_bool_t           visibility;
-    float                   alpha;
+    pepper_bool_t           mapped;
 
     /* Content. */
     pepper_surface_t       *surface;
-    struct wl_listener      surface_destroy_listener;
     struct wl_list          surface_link;
-
-    struct {
-        int x, y, w, h;
-    } viewport;
-
-    /* Clip. */
-    pepper_bool_t           clip_to_parent;
-    pixman_region32_t       clip_region;
+    struct wl_listener      surface_destroy_listener;
 
     pixman_region32_t       opaque_region;
     pixman_region32_t       visible_region;
-    pepper_bool_t           need_damage;
-
-    pepper_list_t           compositor_link;
 };
 
 void
-pepper_compositor_update_view_list(pepper_compositor_t *compositor);
-
-struct pepper_layer
-{
-    pepper_object_t         base;
-    pepper_compositor_t    *compositor;
-    struct wl_list          link;
-    struct wl_list          views;
-};
+pepper_compositor_update_views(pepper_compositor_t *compositor);
 
 /* Event hook */
 struct pepper_event_hook
index 92983ee..d2a29c2 100644 (file)
@@ -125,6 +125,7 @@ struct pepper_list
 {
     pepper_list_t  *prev;
     pepper_list_t  *next;
+    pepper_bool_t   owns_mem;
     void           *item;
 };
 
@@ -155,12 +156,13 @@ pepper_list_insert_item(pepper_list_t *list, void *item)
         return NULL;
 
     elm->item = item;
+    elm->owns_mem = PEPPER_TRUE;
     pepper_list_insert(list, elm);
     return elm;
 }
 
 static inline void
-pepper_list_remove(pepper_list_t *list, pepper_free_func_t free_func, pepper_bool_t free_list)
+pepper_list_remove(pepper_list_t *list, pepper_free_func_t free_func)
 {
     list->prev->next = list->next;
     list->next->prev = list->prev;
@@ -170,13 +172,12 @@ pepper_list_remove(pepper_list_t *list, pepper_free_func_t free_func, pepper_boo
     if (free_func)
         free_func(list->item);
 
-    if (free_list)
+    if (list->owns_mem)
         free(list);
 }
 
 static inline void
-pepper_list_remove_item(pepper_list_t *list, void *item,
-                        pepper_free_func_t free_func, pepper_bool_t free_list)
+pepper_list_remove_item(pepper_list_t *list, void *item, pepper_free_func_t free_func)
 {
     pepper_list_t *l;
 
@@ -184,14 +185,14 @@ pepper_list_remove_item(pepper_list_t *list, void *item,
     {
         if (l->item == item)
         {
-            pepper_list_remove(l, free_func, free_list);
+            pepper_list_remove(l, free_func);
             return;
         }
     }
 }
 
 static inline void
-pepper_list_clear(pepper_list_t *list, pepper_free_func_t free_func, pepper_bool_t free_list)
+pepper_list_clear(pepper_list_t *list, pepper_free_func_t free_func)
 {
     pepper_list_t *l, *temp;
 
@@ -200,7 +201,7 @@ pepper_list_clear(pepper_list_t *list, pepper_free_func_t free_func, pepper_bool
         if (free_func)
             free_func(l->item);
 
-        if (free_list)
+        if (l->owns_mem)
             free(l);
     }
 
index e963714..77cd0b9 100644 (file)
@@ -228,14 +228,7 @@ pepper_buffer_get_resource(pepper_object_t *buffer);
 
 /* View. */
 PEPPER_API pepper_object_t *
-pepper_compositor_add_view(pepper_object_t *compositor,
-                           pepper_object_t *parent, pepper_object_t *pos, pepper_object_t *surface);
-
-PEPPER_API pepper_object_t *
-pepper_compositor_get_top_root_view(pepper_object_t *compositor);
-
-PEPPER_API pepper_object_t *
-pepper_compositor_get_bottom_root_view(pepper_object_t *compositor);
+pepper_compositor_add_surface_view(pepper_object_t *compositor, pepper_object_t *surface);
 
 PEPPER_API void
 pepper_view_destroy(pepper_object_t *view);
@@ -244,22 +237,25 @@ PEPPER_API pepper_object_t *
 pepper_view_get_compositor(pepper_object_t *view);
 
 PEPPER_API pepper_object_t *
-pepper_view_get_parent(pepper_object_t *view);
+pepper_view_get_surface(pepper_object_t *view);
+
+PEPPER_API void
+pepper_view_set_parent(pepper_object_t *view, pepper_object_t *parent);
 
 PEPPER_API pepper_object_t *
-pepper_view_get_surface(pepper_object_t *view);
+pepper_view_get_parent(pepper_object_t *view);
 
 PEPPER_API pepper_bool_t
-pepper_view_stack_above(pepper_object_t *view, pepper_object_t *below);
+pepper_view_stack_above(pepper_object_t *view, pepper_object_t *below, pepper_bool_t subtree);
 
 PEPPER_API pepper_bool_t
-pepper_view_stack_below(pepper_object_t *view, pepper_object_t *above);
+pepper_view_stack_below(pepper_object_t *view, pepper_object_t *above, pepper_bool_t subtree);
 
 PEPPER_API void
-pepper_view_stack_top(pepper_object_t *view);
+pepper_view_stack_top(pepper_object_t *view, pepper_bool_t subtree);
 
 PEPPER_API void
-pepper_view_stack_bottom(pepper_object_t *view);
+pepper_view_stack_bottom(pepper_object_t *view, pepper_bool_t subtree);
 
 PEPPER_API pepper_object_t *
 pepper_view_get_above(pepper_object_t *view);
@@ -267,23 +263,20 @@ pepper_view_get_above(pepper_object_t *view);
 PEPPER_API pepper_object_t *
 pepper_view_get_below(pepper_object_t *view);
 
-PEPPER_API pepper_object_t *
-pepper_view_get_top_child(pepper_object_t *view);
-
-PEPPER_API pepper_object_t *
-pepper_view_get_bottom_child(pepper_object_t *view);
+PEPPER_API const pepper_list_t *
+pepper_view_get_children_list(pepper_object_t *view);
 
 PEPPER_API void
-pepper_view_resize(pepper_object_t *view, float w, float h);
+pepper_view_resize(pepper_object_t *view, double w, double h);
 
 PEPPER_API void
-pepper_view_get_size(pepper_object_t *view, float *w, float *h);
+pepper_view_get_size(pepper_object_t *view, double *w, double *h);
 
 PEPPER_API void
-pepper_view_set_position(pepper_object_t *view, float x, float y);
+pepper_view_set_position(pepper_object_t *view, double x, double y);
 
 PEPPER_API void
-pepper_view_get_position(pepper_object_t *view, float *x, float *y);
+pepper_view_get_position(pepper_object_t *view, double *x, double *y);
 
 PEPPER_API void
 pepper_view_set_transform(pepper_object_t *view, const pepper_matrix_t *matrix);
@@ -292,37 +285,19 @@ PEPPER_API const pepper_matrix_t *
 pepper_view_get_transform(pepper_object_t *view);
 
 PEPPER_API void
-pepper_view_set_visibility(pepper_object_t *view, pepper_bool_t visibility);
-
-PEPPER_API pepper_bool_t
-pepper_view_get_visibility(pepper_object_t *view);
-
-PEPPER_API const pixman_region32_t *
-pepper_view_get_visible_region(pepper_object_t *view);
+pepper_view_map(pepper_object_t *view);
 
 PEPPER_API void
-pepper_view_set_alpha(pepper_object_t *view, float alpha);
-
-PEPPER_API float
-pepper_view_get_alpha(pepper_object_t *view);
-
-PEPPER_API void
-pepper_view_set_viewport(pepper_object_t *view, int x, int y, int w, int h);
-
-PEPPER_API void
-pepper_view_get_viewport(pepper_object_t *view, int *x, int *y, int *w, int *h);
-
-PEPPER_API void
-pepper_view_set_clip_to_parent(pepper_object_t *view, pepper_bool_t clip);
+pepper_view_unmap(pepper_object_t *view);
 
 PEPPER_API pepper_bool_t
-pepper_view_get_clip_to_parent(pepper_object_t *view);
+pepper_view_is_mapped(pepper_object_t *view);
 
 PEPPER_API pepper_bool_t
-pepper_view_set_clip_region(pepper_object_t *view, const pixman_region32_t *region);
+pepper_view_is_visible(pepper_object_t *view);
 
 PEPPER_API const pixman_region32_t *
-pepper_view_get_clip_region(pepper_object_t *view);
+pepper_view_get_visible_region(pepper_object_t *view);
 
 #ifdef __cplusplus
 }
index 46271ba..ecb4898 100644 (file)
@@ -2,7 +2,7 @@
 #include <string.h>
 
 static void
-handle_surface_destroy(struct wl_listener *listener, void *data)
+view_handle_surface_destroy(struct wl_listener *listener, void *data)
 {
     pepper_view_t *view = pepper_container_of(listener, pepper_view_t, surface_destroy_listener);
     PEPPER_ASSERT(view->surface != NULL);
@@ -10,158 +10,150 @@ handle_surface_destroy(struct wl_listener *listener, void *data)
 }
 
 static void
-damage_region_transform(pixman_region32_t *region, pepper_matrix_t *matrix)
+view_geometry_dirty(pepper_view_t *view)
 {
-    /* TODO: */
+    pepper_list_t *l;
+
+    if (view->geometry_dirty)
+        return;
+
+    view->geometry_dirty = PEPPER_TRUE;
+    pepper_compositor_add_damage(view->compositor, &view->visible_region);
+
+    PEPPER_LIST_FOR_EACH(&view->children_list, l)
+        view_geometry_dirty((pepper_view_t *)l->item);
 }
 
 static void
-view_damage_below_consume(pepper_view_t *view)
+view_update_visibility(pepper_view_t *view)
 {
-    pepper_compositor_add_damage(view->compositor, &view->visible_region);
-    pixman_region32_init(&view->visible_region);
+    pepper_bool_t visibility;
+
+    if (view->parent)
+        visibility = view->parent->visibility && view->mapped;
+    else
+        visibility = view->mapped;
+
+    if (visibility != view->visibility)
+    {
+        pepper_list_t *l;
+
+        view->visibility = visibility;
+
+        /* We simply treat a visibility change as a geometry change. */
+        view_geometry_dirty(view);
+
+        PEPPER_LIST_FOR_EACH(&view->children_list, l)
+            view_update_visibility((pepper_view_t *)l->item);
+    }
 }
 
 static void
-view_geometry_dirty(pepper_view_t *view)
+view_map(pepper_view_t *view)
 {
-    pepper_view_t *child;
-
-    if (view->geometry_dirty)
+    if (view->mapped)
         return;
 
-    view->geometry_dirty = PEPPER_TRUE;
+    view->mapped = PEPPER_TRUE;
+    view_update_visibility(view);
+}
 
-    view_damage_below_consume(view);
-    view->need_damage = PEPPER_TRUE;
+static void
+view_unmap(pepper_view_t *view)
+{
+    if (!view->mapped)
+        return;
 
-    wl_list_for_each(child, &view->child_list, parent_link)
-        view_geometry_dirty(child);
+    view->mapped = PEPPER_FALSE;
+    view_update_visibility(view);
 }
 
 PEPPER_API pepper_object_t *
-pepper_compositor_add_view(pepper_object_t *comp,
-                           pepper_object_t *par, pepper_object_t *pos, pepper_object_t *sfc)
+pepper_compositor_add_surface_view(pepper_object_t *comp, pepper_object_t *sfc)
 {
     pepper_view_t       *view;
     pepper_compositor_t *compositor = (pepper_compositor_t *)comp;
-    pepper_view_t       *parent = (pepper_view_t *)par;
-    pepper_view_t       *position = (pepper_view_t *)pos;
-    pepper_surface_t    *surface = (pepper_surface_t *)sfc;
 
     CHECK_MAGIC_AND_NON_NULL(comp, PEPPER_COMPOSITOR);
-    CHECK_MAGIC_IF_NON_NULL(par, PEPPER_VIEW);
-    CHECK_MAGIC_IF_NON_NULL(pos, PEPPER_VIEW);
     CHECK_MAGIC_IF_NON_NULL(sfc, PEPPER_SURFACE);
 
     view = (pepper_view_t *)pepper_object_alloc(sizeof(pepper_view_t), PEPPER_VIEW);
     if (!view)
     {
-        PEPPER_ERROR("Failed to allocate memory.\n");
+        PEPPER_ERROR("Failed to allocate a pepper object.\n");
         return NULL;
     }
 
     view->compositor = compositor;
-    view->parent = parent;
 
-    wl_list_init(&view->child_list);
+    view->x = 0.0;
+    view->y = 0.0;
+    view->w = 0.0;
+    view->h = 0.0;
+
     pepper_matrix_init_identity(&view->transform);
-    view->alpha = 1.0f;
+    pepper_matrix_init_identity(&view->matrix_to_parent);
+    pepper_matrix_init_identity(&view->matrix_to_global);
 
-    view->surface = surface;
+    view->parent_link.item = (void *)view;
+    view->z_link.item = (void *)view;
 
-    if (surface)
-    {
-        wl_list_insert(surface->view_list.next, &view->surface_link);
-        view->surface_destroy_listener.notify = handle_surface_destroy;
-        pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener);
-    }
-    else
+    pepper_list_init(&view->children_list);
+    pepper_list_insert(compositor->root_view_list.prev, &view->parent_link);
+    pepper_list_insert(compositor->view_list.prev, &view->z_link);
+
+    if (sfc)
     {
-        wl_list_init(&view->surface_link);
-    }
+        pepper_surface_t *surface = (pepper_surface_t *)sfc;
 
-    pixman_region32_init(&view->clip_region);
-    pixman_region32_init(&view->visible_region);
+        view->surface = surface;
+        wl_list_insert(&surface->view_list, &view->surface_link);
 
-    if (position)
-        wl_list_insert(position->parent_link.next, &view->parent_link);
-    else if (parent)
-        wl_list_insert(parent->child_list.next, &view->parent_link);
-    else
-        wl_list_insert(compositor->root_view_list.next, &view->parent_link);
+        view->surface_destroy_listener.notify = view_handle_surface_destroy;
+        pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener);
 
-    if (parent)
-        view->container_list = &parent->child_list;
-    else
-        view->container_list = &compositor->root_view_list;
+        view->w = surface->w;
+        view->h = surface->h;
+    }
 
-    view->compositor_link.item = (void *)view;
-    view_geometry_dirty(view);
+    pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h);
+    pixman_region32_init(&view->opaque_region);
+    pixman_region32_init(&view->visible_region);
 
     return &view->base;
 }
 
-PEPPER_API pepper_object_t *
-pepper_compositor_get_top_root_view(pepper_object_t *comp)
-{
-    pepper_compositor_t *compositor = (pepper_compositor_t *)comp;
-    CHECK_MAGIC_AND_NON_NULL(comp, PEPPER_COMPOSITOR);
-
-    if (wl_list_empty(&compositor->root_view_list))
-        return NULL;
-
-    return &pepper_container_of(compositor->root_view_list.prev, pepper_view_t, parent_link)->base;
-}
-
-PEPPER_API pepper_object_t *
-pepper_compositor_get_bottom_root_view(pepper_object_t *comp)
-{
-    pepper_compositor_t *compositor = (pepper_compositor_t *)comp;
-    CHECK_MAGIC_AND_NON_NULL(comp, PEPPER_COMPOSITOR);
-
-    if (wl_list_empty(&compositor->root_view_list))
-        return NULL;
-
-    return &pepper_container_of(compositor->root_view_list.next, pepper_view_t, parent_link)->base;
-}
-
-static void
-pepper_view_unmap(pepper_view_t *view)
-{
-    pepper_view_t *child;
-
-    if (!view->visibility)
-        return;
-
-    wl_list_for_each(child, &view->child_list, parent_link)
-        pepper_view_unmap(child);
-
-    view->visibility = PEPPER_FALSE;
-    view_damage_below_consume(view);
-}
-
 PEPPER_API void
 pepper_view_destroy(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
-    pepper_view_t *child, *next;
+    pepper_view_t  *view = (pepper_view_t *)v;
+    pepper_list_t  *l, *next;
 
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
+    /* Destroy signal is emitted in here so that any children that are willing to survive this
+     * destruction can detach from their parent.
+     */
     pepper_object_fini(&view->base);
-    pepper_view_unmap(view);
+    view_unmap(view);
 
-    /* Destroy all child views. */
-    wl_list_for_each_safe(child, next, &view->child_list, parent_link)
-        pepper_view_destroy(&child->base);
+    PEPPER_LIST_FOR_EACH_SAFE(&view->children_list, l, next)
+        pepper_view_destroy((pepper_object_t *)(l->item));
 
-    wl_list_remove(&view->parent_link);
+    PEPPER_ASSERT(pepper_list_empty(&view->children_list));
+
+    pepper_list_remove(&view->parent_link, NULL);
+    pepper_list_remove(&view->z_link, NULL);
 
     if (view->surface)
+    {
         wl_list_remove(&view->surface_link);
+        wl_list_remove(&view->surface_destroy_listener.link);
+    }
 
-    pixman_region32_fini(&view->clip_region);
+    pixman_region32_fini(&view->opaque_region);
+    pixman_region32_fini(&view->visible_region);
+    pixman_region32_fini(&view->bounding_region);
 
     pepper_free(view);
 }
@@ -169,178 +161,162 @@ pepper_view_destroy(pepper_object_t *v)
 PEPPER_API pepper_object_t *
 pepper_view_get_compositor(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return &view->compositor->base;
+    return &((pepper_view_t *)v)->compositor->base;
 }
 
 PEPPER_API pepper_object_t *
-pepper_view_get_parent(pepper_object_t *v)
+pepper_view_get_surface(pepper_object_t *v)
 {
     pepper_view_t *view = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return &view->parent->base;
+
+    if (view->surface)
+        return &((pepper_view_t *)view)->surface->base;
+
+    return NULL;
 }
 
-PEPPER_API pepper_object_t *
-pepper_view_get_surface(pepper_object_t *v)
+PEPPER_API void
+pepper_view_set_parent(pepper_object_t *v, pepper_object_t *p)
 {
     pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *parent = (pepper_view_t *)p;
+
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return &view->surface->base;
+    CHECK_MAGIC_IF_NON_NULL(p, PEPPER_VIEW);
+
+    if (view->parent == parent)
+        return;
+
+    view->parent = parent;
+    pepper_list_remove(&view->parent_link, NULL);
+
+    if (view->parent)
+        pepper_list_insert(view->parent->children_list.prev, &view->parent_link);
+    else
+        pepper_list_insert(view->compositor->root_view_list.prev, &view->parent_link);
+
+    view_geometry_dirty(view);
 }
 
-PEPPER_API pepper_bool_t
-pepper_view_stack_above(pepper_object_t *v, pepper_object_t *blw)
+PEPPER_API pepper_object_t *
+pepper_view_get_parent(pepper_object_t *v)
 {
     pepper_view_t *view = (pepper_view_t *)v;
-    pepper_view_t *below = (pepper_view_t *)blw;
-
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    CHECK_MAGIC_AND_NON_NULL(blw, PEPPER_VIEW);
+    return &view->parent->base;
+}
+
+static pepper_list_t *
+view_insert(pepper_view_t *view, pepper_list_t *pos, pepper_bool_t subtree)
+{
+    if (pos->next != &view->z_link)
+    {
+        pepper_list_remove(&view->z_link, NULL);
+        pepper_list_insert(pos, &view->z_link);
 
-    if (view == below)
-        return PEPPER_TRUE;
+        if (view->visibility)
+            pepper_compositor_add_damage(view->compositor, &view->visible_region);
+    }
 
-    if (view->parent != below->parent)
-        return PEPPER_FALSE;
+    pos = &view->z_link;
 
-    wl_list_remove(&view->parent_link);
-    wl_list_insert(below->parent_link.next, &view->parent_link);
+    if (subtree)
+    {
+        pepper_list_t *l;
 
-    view_damage_below_consume(view);
-    view->need_damage = PEPPER_TRUE;
+        PEPPER_LIST_FOR_EACH(&view->children_list, l)
+            pos = view_insert((pepper_view_t *)l->item, pos, subtree);
+    }
 
-    return PEPPER_TRUE;
+    return pos;
 }
 
 PEPPER_API pepper_bool_t
-pepper_view_stack_below(pepper_object_t *v, pepper_object_t *abv)
+pepper_view_stack_above(pepper_object_t *v, pepper_object_t *b, pepper_bool_t subtree)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
-    pepper_view_t *above = (pepper_view_t *)abv;
+    pepper_view_t *view  = (pepper_view_t *)v;
+    pepper_view_t *below = (pepper_view_t *)b;
 
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    CHECK_MAGIC_AND_NON_NULL(abv, PEPPER_VIEW);
+    CHECK_MAGIC_AND_NON_NULL(b, PEPPER_VIEW);
 
-    if (view == above)
-        return PEPPER_TRUE;
-
-    if (view->parent != above->parent)
-        return PEPPER_FALSE;
+    view_insert(view, &below->z_link, subtree);
+    return PEPPER_TRUE;
+}
 
-    wl_list_remove(&view->parent_link);
-    wl_list_insert(above->parent_link.prev, &view->parent_link);
+PEPPER_API pepper_bool_t
+pepper_view_stack_below(pepper_object_t *v, pepper_object_t *a, pepper_bool_t subtree)
+{
+    pepper_view_t *view  = (pepper_view_t *)v;
+    pepper_view_t *above = (pepper_view_t *)a;
 
-    view_damage_below_consume(view);
-    view->need_damage = PEPPER_TRUE;
+    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
+    CHECK_MAGIC_AND_NON_NULL(a, PEPPER_VIEW);
 
+    view_insert(view, above->z_link.prev, subtree);
     return PEPPER_TRUE;
 }
 
 PEPPER_API void
-pepper_view_stack_top(pepper_object_t *v)
+pepper_view_stack_top(pepper_object_t *v, pepper_bool_t subtree)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->container_list->prev == &view->parent_link)
-        return;
-
-    wl_list_remove(&view->parent_link);
-    wl_list_insert(view->container_list->prev, &view->parent_link);
-
-    view_damage_below_consume(view);
-    view->need_damage = PEPPER_TRUE;
+    view_insert(view, view->compositor->view_list.prev, subtree);
 }
 
 PEPPER_API void
-pepper_view_stack_bottom(pepper_object_t *v)
+pepper_view_stack_bottom(pepper_object_t *v, pepper_bool_t subtree)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->container_list->next == &view->parent_link)
-        return;
-
-    wl_list_remove(&view->parent_link);
-    wl_list_insert(view->container_list, &view->parent_link);
-
-    view_damage_below_consume(view);
-    view->need_damage = PEPPER_TRUE;
+    view_insert(view, &view->compositor->view_list, subtree);
 }
 
 PEPPER_API pepper_object_t *
 pepper_view_get_above(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->parent_link.next == view->container_list)
-        return NULL;
-
-    return &pepper_container_of(view->parent_link.next, pepper_view_t, parent_link)->base;
+    return view->z_link.next->item;
 }
 
 PEPPER_API pepper_object_t *
 pepper_view_get_below(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->parent_link.next == view->container_list)
-        return NULL;
-
-    return &pepper_container_of(view->parent_link.prev, pepper_view_t, parent_link)->base;
-}
-
-
-PEPPER_API pepper_object_t *
-pepper_view_get_top_child(pepper_object_t *v)
-{
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (wl_list_empty(&view->child_list))
-        return NULL;
-
-    return &pepper_container_of(view->child_list.prev, pepper_view_t, parent_link)->base;
+    return view->z_link.prev->item;
 }
 
-PEPPER_API pepper_object_t *
-pepper_view_get_bottom_child(pepper_object_t *v)
+PEPPER_API const pepper_list_t *
+pepper_view_get_children_list(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (wl_list_empty(&view->child_list))
-        return NULL;
-
-    return &pepper_container_of(view->child_list.next, pepper_view_t, parent_link)->base;
+    return &view->children_list;
 }
 
 PEPPER_API void
-pepper_view_resize(pepper_object_t *v, float w, float h)
+pepper_view_resize(pepper_object_t *v, double w, double h)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
-    if (w < 0.0f)
-        w = 0.0f;
-
-   if (h < 0.0f)
-       h = 0.0f;
+    if (view->w == w && view->h == h)
+        return;
 
     view->w = w;
     view->h = h;
-
     view_geometry_dirty(view);
 }
 
 PEPPER_API void
-pepper_view_get_size(pepper_object_t *v, float *w, float *h)
+pepper_view_get_size(pepper_object_t *v, double *w, double *h)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
     if (w)
@@ -351,21 +327,23 @@ pepper_view_get_size(pepper_object_t *v, float *w, float *h)
 }
 
 PEPPER_API void
-pepper_view_set_position(pepper_object_t *v, float x, float y)
+pepper_view_set_position(pepper_object_t *v, double x, double y)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
+    if (view->x == x && view->y == y)
+        return;
+
     view->x = x;
     view->y = y;
-
     view_geometry_dirty(view);
 }
 
 PEPPER_API void
-pepper_view_get_position(pepper_object_t *v, float *x, float *y)
+pepper_view_get_position(pepper_object_t *v, double *x, double *y)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
     if (x)
@@ -378,158 +356,75 @@ pepper_view_get_position(pepper_object_t *v, float *x, float *y)
 PEPPER_API void
 pepper_view_set_transform(pepper_object_t *v, const pepper_matrix_t *matrix)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
 
-    memcpy(&view->transform, matrix, sizeof(pepper_matrix_t));
+    pepper_matrix_copy(&view->transform, matrix);
     view_geometry_dirty(view);
 }
 
 PEPPER_API const pepper_matrix_t *
 pepper_view_get_transform(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
     return &view->transform;
 }
 
 PEPPER_API void
-pepper_view_set_visibility(pepper_object_t *v, pepper_bool_t visibility)
-{
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->visibility == visibility)
-        return;
-
-    view->visibility = visibility;
-    view_damage_below_consume(view);
-}
-
-PEPPER_API pepper_bool_t
-pepper_view_get_visibility(pepper_object_t *v)
-{
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return view->visibility;
-}
-
-PEPPER_API const pixman_region32_t *
-pepper_view_get_visible_region(pepper_object_t *v)
+pepper_view_map(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return &view->visible_region;
+    view_map(view);
 }
 
 PEPPER_API void
-pepper_view_set_alpha(pepper_object_t *v, float alpha)
-{
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (alpha < 0.0f)
-        alpha = 0.0f;
-
-    if (alpha > 1.0f)
-        alpha = 1.0f;
-
-    if (view->alpha == alpha)
-        return;
-
-    view->alpha = alpha;
-    view_damage_below_consume(view);
-}
-
-PEPPER_API float
-pepper_view_get_alpha(pepper_object_t *v)
+pepper_view_unmap(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return view->alpha;
+    view_unmap(view);
 }
 
-PEPPER_API void
-pepper_view_set_viewport(pepper_object_t *v, int x, int y, int w, int h)
-{
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->viewport.x == x && view->viewport.y == y &&
-        view->viewport.w == w && view->viewport.h == h)
-        return;
-
-    view->viewport.x = x;
-    view->viewport.y = y;
-    view->viewport.w = w;
-    view->viewport.h = h;
-
-    view_damage_below_consume(view);
-}
-
-PEPPER_API void
-pepper_view_get_viewport(pepper_object_t *v, int *x, int *y, int *w, int *h)
+PEPPER_API pepper_bool_t
+pepper_view_is_mapped(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (x)
-        *x = view->viewport.x;
-
-    if (y)
-        *y = view->viewport.y;
-
-    if (w)
-        *w = view->viewport.w;
-
-    if (h)
-        *h = view->viewport.h;
+    return view->mapped;
 }
 
-PEPPER_API void
-pepper_view_set_clip_to_parent(pepper_object_t *v, pepper_bool_t clip)
+PEPPER_API pepper_bool_t
+pepper_view_is_visible(pepper_object_t *v)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
+    pepper_view_t *view  = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (view->clip_to_parent == clip)
-        return;
-
-    view->clip_to_parent = clip;
-    view_damage_below_consume(view);
+    return view->visibility;
 }
 
-PEPPER_API pepper_bool_t
-pepper_view_get_clip_to_parent(pepper_object_t *v)
+PEPPER_API const pixman_region32_t *
+pepper_view_get_visible_region(pepper_object_t *v)
 {
     pepper_view_t *view = (pepper_view_t *)v;
     CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return view->clip_to_parent;
+    return &view->visible_region;
 }
 
-PEPPER_API pepper_bool_t
-pepper_view_set_clip_region(pepper_object_t *v, const pixman_region32_t *region)
+static void
+view_update_bounding_region(pepper_view_t *view)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-
-    if (!pixman_region32_copy(&view->clip_region, (pixman_region32_t *)region))
-        return PEPPER_FALSE;
-
-    view_damage_below_consume(view);
-    return PEPPER_TRUE;
+    /* TODO: */
 }
 
-PEPPER_API const pixman_region32_t *
-pepper_view_get_clip_region(pepper_object_t *v)
+static void
+view_update_opaque_region(pepper_view_t *view)
 {
-    pepper_view_t *view = (pepper_view_t *)v;
-    CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW);
-    return &view->clip_region;
+    /* TODO: */
 }
 
 static void
-view_update_bounding_region(pepper_view_t *view)
+damage_region_transform(pixman_region32_t *region, const pepper_matrix_t *matrix)
 {
     /* TODO: */
 }
@@ -573,73 +468,56 @@ view_update_geometry(pepper_view_t *view)
         }
 
         view_update_bounding_region(view);
+        view_update_opaque_region(view);
+
         view->geometry_dirty = PEPPER_FALSE;
     }
 }
 
-static void
-view_list_add(pepper_view_t *view)
-{
-    pepper_view_t *child;
-
-    pepper_list_insert(&view->compositor->view_list, &view->compositor_link);
-
-    wl_list_for_each(child, &view->child_list, parent_link)
-        view_list_add(child);
-}
-
 void
-pepper_compositor_update_view_list(pepper_compositor_t *compositor)
+pepper_compositor_update_views(pepper_compositor_t *compositor)
 {
-    pepper_view_t      *view;
+    pepper_list_t      *l;
     pixman_region32_t   visible;
     pixman_region32_t   opaque;
     pixman_region32_t   surface_damage;
-    pepper_list_t      *l;
+    pixman_region32_t   damage;
 
     pixman_region32_init(&visible);
     pixman_region32_init(&opaque);
     pixman_region32_init(&surface_damage);
-
-    /* Make compositor's view list empty. */
-    pepper_list_init(&compositor->view_list);
-
-    /* Build z-ordered view list by traversing the view tree in depth-first order. */
-    wl_list_for_each(view, &compositor->root_view_list, parent_link)
-        view_list_add(view);
+    pixman_region32_init(&damage);
 
     /* Update views from front to back. */
     PEPPER_LIST_FOR_EACH_REVERSE(&compositor->view_list, l)
     {
-        view = l->item;
+        pepper_view_t *view = l->item;
+
         view_update_geometry(view);
 
-        /* Update visible region. */
-        pixman_region32_subtract(&view->visible_region, &view->bounding_region, &opaque);
+        /* Calculate updated visible region. */
+        pixman_region32_subtract(&visible, &view->bounding_region, &opaque);
+        pixman_region32_subtract(&damage, &visible, &view->visible_region);
 
-        /* Inflict damage caused by geometry and z-order change. */
-        if (view->need_damage)
-        {
-            pepper_compositor_add_damage(view->compositor, &view->visible_region);
-            view->need_damage = PEPPER_FALSE;
-        }
+        /* Inflict damage for the visible region change. */
+        pepper_compositor_add_damage(view->compositor, &damage);
+
+        /* Update visible region of the view. */
+        pixman_region32_copy(&view->visible_region, &visible);
 
         /* Inflict surface damage. */
         if (pixman_region32_not_empty(&view->surface->damage_region))
         {
             pepper_surface_flush_damage(view->surface);
 
-            /* Intersect surface damage region with viewport rectangle. */
-            pixman_region32_intersect_rect(&surface_damage, &view->surface->damage_region,
-                                           view->viewport.x, view->viewport.y,
-                                           view->viewport.w, view->viewport.h);
-
-            /* Translate surface damage to compensate viewport offset. */
-            pixman_region32_translate(&surface_damage, -view->viewport.x, -view->viewport.y);
+            pixman_region32_copy(&surface_damage, &view->surface->damage_region);
 
             /* Transform surface damage into global coordinate space. */
             damage_region_transform(&surface_damage, &view->matrix_to_global);
 
+            /* Clip surface damage with view's bounding region. */
+            pixman_region32_intersect(&surface_damage, &surface_damage, &view->bounding_region);
+
             /* Subtract area covered by opaque views. */
             pixman_region32_subtract(&surface_damage, &surface_damage, &opaque);
 
@@ -649,4 +527,9 @@ pepper_compositor_update_view_list(pepper_compositor_t *compositor)
         /* Accumulate opaque region. */
         pixman_region32_union(&opaque, &opaque, &view->opaque_region);
     }
+
+    pixman_region32_fini(&visible);
+    pixman_region32_fini(&opaque);
+    pixman_region32_fini(&surface_damage);
+    pixman_region32_fini(&damage);
 }