compositor: Organize surface stack using new struct weston_layer
authorKristian Høgsberg <krh@bitplanet.net>
Wed, 29 Feb 2012 17:42:35 +0000 (12:42 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 1 Mar 2012 22:33:51 +0000 (17:33 -0500)
The surface data structure is now a list of list of surfaces.  The core
compositor defines the fade and cursor layer, and it's up to the shell to
provide more layers for the various surface types it implements.

src/compositor.c
src/compositor.h
src/shell.c

index 679894b..95513da 100644 (file)
@@ -211,6 +211,7 @@ weston_surface_create(struct weston_compositor *compositor)
        wl_list_init(&surface->surface.resource.destroy_listener_list);
 
        wl_list_init(&surface->link);
+       wl_list_init(&surface->layer_link);
        wl_list_init(&surface->buffer_link);
 
        surface->surface.resource.client = NULL;
@@ -600,6 +601,7 @@ weston_surface_unmap(struct weston_surface *surface)
        weston_surface_damage_below(surface);
        surface->output = NULL;
        wl_list_remove(&surface->link);
+       wl_list_remove(&surface->layer_link);
        weston_compositor_repick(surface->compositor);
        weston_compositor_schedule_repaint(surface->compositor);
 }
@@ -808,37 +810,15 @@ out:
        pixman_region32_fini(&repaint);
 }
 
-WL_EXPORT struct wl_list *
-weston_compositor_top(struct weston_compositor *compositor)
-{
-       struct weston_input_device *input_device;
-       struct wl_list *list;
-
-       input_device = (struct weston_input_device *) compositor->input_device;
-
-       /* Insert below pointer */
-       list = &compositor->surface_list;
-       if (compositor->fade.surface &&
-           list->next == &compositor->fade.surface->link)
-               list = list->next;
-       if (list->next == &input_device->sprite->link)
-               list = list->next;
-       if (input_device->drag_surface &&
-           list->next == &input_device->drag_surface->link)
-               list = list->next;
-
-       return list;
-}
-
-static void
-weston_surface_raise(struct weston_surface *surface)
+WL_EXPORT void
+weston_surface_restack(struct weston_surface *surface, struct wl_list *below)
 {
        struct weston_compositor *compositor = surface->compositor;
-       struct wl_list *list = weston_compositor_top(compositor);
 
-       wl_list_remove(&surface->link);
-       wl_list_insert(list, &surface->link);
+       wl_list_remove(&surface->layer_link);
+       wl_list_insert(below, &surface->layer_link);
        weston_compositor_repick(compositor);
+       weston_surface_damage_below(surface);
        weston_surface_damage(surface);
 }
 
@@ -912,6 +892,7 @@ weston_output_repaint(struct weston_output *output, int msecs)
 {
        struct weston_compositor *ec = output->compositor;
        struct weston_surface *es;
+       struct weston_layer *layer;
        struct weston_animation *animation, *next;
        struct weston_frame_callback *cb, *cnext;
        pixman_region32_t opaque, new_damage, output_damage;
@@ -925,10 +906,14 @@ weston_output_repaint(struct weston_output *output, int msecs)
                output->border.top + output->border.bottom;
        glViewport(0, 0, width, height);
 
-       wl_list_for_each(es, &ec->surface_list, link)
-               /* Update surface transform now to avoid calling it ever
-                * again from the repaint sub-functions. */
-               weston_surface_update_transform(es);
+       /* Rebuild the surface list and update surface transforms up front. */
+       wl_list_init(&ec->surface_list);
+       wl_list_for_each(layer, &ec->layer_list, link) {
+               wl_list_for_each(es, &layer->surface_list, layer_link) {
+                       weston_surface_update_transform(es);
+                       wl_list_insert(ec->surface_list.prev, &es->link);
+               }
+       }
 
        if (output->assign_planes)
                /*
@@ -1003,6 +988,13 @@ weston_output_finish_frame(struct weston_output *output, int msecs)
 }
 
 WL_EXPORT void
+weston_layer_init(struct weston_layer *layer, struct wl_list *below)
+{
+       wl_list_init(&layer->surface_list);
+       wl_list_insert(below, &layer->link);
+}
+
+WL_EXPORT void
 weston_compositor_schedule_repaint(struct weston_compositor *compositor)
 {
        struct weston_output *output;
@@ -1041,7 +1033,8 @@ weston_compositor_fade(struct weston_compositor *compositor, float tint)
                surface = weston_surface_create(compositor);
                weston_surface_configure(surface, 0, 0, 8192, 8192);
                weston_surface_set_color(surface, 0.0, 0.0, 0.0, 0.0);
-               wl_list_insert(&compositor->surface_list, &surface->link);
+               wl_list_insert(&compositor->fade_layer.surface_list,
+                              &surface->layer_link);
                weston_surface_assign_output(surface);
                compositor->fade.surface = surface;
                pixman_region32_init(&surface->input);
@@ -1489,7 +1482,6 @@ WL_EXPORT void
 weston_surface_activate(struct weston_surface *surface,
                        struct weston_input_device *device, uint32_t time)
 {
-       weston_surface_raise(surface);
        wl_input_device_set_keyboard_focus(&device->input_device,
                                           &surface->surface, time);
        wl_data_device_set_keyboard_focus(&device->input_device);
@@ -1814,13 +1806,14 @@ input_device_attach(struct wl_client *client,
 
        if (!buffer_resource && device->sprite->output) {
                wl_list_remove(&device->sprite->link);
+               wl_list_remove(&device->sprite->layer_link);
                device->sprite->output = NULL;
                return;
        }
 
        if (!device->sprite->output) {
-               wl_list_insert(&compositor->surface_list,
-                              &device->sprite->link);
+               wl_list_insert(&compositor->cursor_layer.surface_list,
+                              &device->sprite->layer_link);
                weston_surface_assign_output(device->sprite);
        }
 
@@ -1924,8 +1917,8 @@ weston_input_update_drag_surface(struct wl_input_device *input_device,
 
        if (device->drag_surface->output == NULL &&
            device->drag_surface->buffer) {
-               wl_list_insert(&device->sprite->link,
-                              &device->drag_surface->link);
+               wl_list_insert(&device->sprite->layer_link,
+                              &device->drag_surface->layer_link);
                weston_surface_assign_output(device->drag_surface);
                empty_region(&device->drag_surface->input);
        }
@@ -2270,6 +2263,7 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)
                ec->bind_display(ec->display, ec->wl_display);
 
        wl_list_init(&ec->surface_list);
+       wl_list_init(&ec->layer_list);
        wl_list_init(&ec->input_device_list);
        wl_list_init(&ec->output_list);
        wl_list_init(&ec->binding_list);
@@ -2278,6 +2272,9 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display)
        ec->fade.animation.frame = fade_frame;
        wl_list_init(&ec->fade.animation.link);
 
+       weston_layer_init(&ec->fade_layer, &ec->layer_list);
+       weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link);
+
        ec->screenshooter = screenshooter_create(ec);
 
        wl_data_device_manager_init(ec->wl_display);
index 9f29c4b..d0b7206 100644 (file)
@@ -163,6 +163,11 @@ enum {
 
 struct screenshooter;
 
+struct weston_layer {
+       struct wl_list surface_list;
+       struct wl_list link;
+};
+
 struct weston_compositor {
        struct wl_shm *shm;
        struct weston_xserver *wxs;
@@ -181,8 +186,12 @@ struct weston_compositor {
        /* There can be more than one, but not right now... */
        struct wl_input_device *input_device;
 
+       struct weston_layer fade_layer;
+       struct weston_layer cursor_layer;
+
        struct wl_list output_list;
        struct wl_list input_device_list;
+       struct wl_list layer_list;
        struct wl_list surface_list;
        struct wl_list binding_list;
        struct wl_list animation_list;
@@ -267,6 +276,7 @@ struct weston_surface {
        pixman_region32_t input;
        int32_t pitch;
        struct wl_list link;
+       struct wl_list layer_link;
        struct wl_list buffer_link;
        struct weston_shader *shader;
        GLfloat color[4];
@@ -372,6 +382,9 @@ notify_touch(struct wl_input_device *device, uint32_t time, int touch_id,
             int x, int y, int touch_type);
 
 void
+weston_layer_init(struct weston_layer *layer, struct wl_list *below);
+
+void
 weston_output_finish_frame(struct weston_output *output, int msecs);
 void
 weston_output_damage(struct weston_output *output);
@@ -424,6 +437,9 @@ weston_surface_configure(struct weston_surface *surface,
                         GLfloat x, GLfloat y, int width, int height);
 
 void
+weston_surface_restack(struct weston_surface *surface, struct wl_list *below);
+
+void
 weston_surface_set_position(struct weston_surface *surface,
                            GLfloat x, GLfloat y);
 
index accc1c5..6afdf3a 100644 (file)
@@ -42,6 +42,12 @@ struct wl_shell {
        struct weston_compositor *compositor;
        struct weston_shell shell;
 
+       struct weston_layer fullscreen_layer;
+       struct weston_layer panel_layer;
+       struct weston_layer toplevel_layer;
+       struct weston_layer background_layer;
+       struct weston_layer lock_layer;
+
        struct {
                struct weston_process process;
                struct wl_client *client;
@@ -56,7 +62,6 @@ struct wl_shell {
 
        struct shell_surface *lock_surface;
        struct wl_listener lock_surface_listener;
-       struct wl_list hidden_surface_list;
 
        struct wl_list backgrounds;
        struct wl_list panels;
@@ -545,11 +550,15 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
        center_on_output(surface, output);
 
        if (!shsurf->fullscreen.black_surface)
-               shsurf->fullscreen.black_surface = create_black_surface(surface->compositor,
-                                                                       output->x, output->y,
-                                                                       output->current->width, output->current->height);
-       wl_list_remove(&shsurf->fullscreen.black_surface->link);
-       wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link);
+               shsurf->fullscreen.black_surface =
+                       create_black_surface(surface->compositor,
+                                            output->x, output->y,
+                                            output->current->width,
+                                            output->current->height);
+
+       wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
+       wl_list_insert(&surface->layer_link,
+                      &shsurf->fullscreen.black_surface->layer_link);
        shsurf->fullscreen.black_surface->output = output;
 
        switch (shsurf->fullscreen.type) {
@@ -580,22 +589,17 @@ shell_stack_fullscreen(struct shell_surface *shsurf)
 {
        struct weston_surface *surface = shsurf->surface;
        struct wl_shell *shell = shell_surface_get_shell(shsurf);
-       struct wl_list *list;
 
-       wl_list_remove(&surface->link);
-       wl_list_remove(&shsurf->fullscreen.black_surface->link);
+       wl_list_remove(&surface->layer_link);
+       wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
 
-       if (shell->locked) {
-               wl_list_insert(&shell->hidden_surface_list, &surface->link);
-               wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link);
-       } else {
-               list = weston_compositor_top(surface->compositor);
-               wl_list_insert(list, &surface->link);
-               wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link);
+       wl_list_insert(&shell->fullscreen_layer.surface_list,
+                      &surface->layer_link);
+       wl_list_insert(&surface->layer_link,
+                      &shsurf->fullscreen.black_surface->layer_link);
 
-               weston_surface_damage(surface);
-               weston_surface_damage(shsurf->fullscreen.black_surface);
-       }
+       weston_surface_damage(surface);
+       weston_surface_damage(shsurf->fullscreen.black_surface);
 }
 
 static void
@@ -902,12 +906,12 @@ show_screensaver(struct wl_shell *shell, struct shell_surface *surface)
        struct wl_list *list;
 
        if (shell->lock_surface)
-               list = &shell->lock_surface->surface->link;
+               list = &shell->lock_surface->surface->layer_link;
        else
-               list = &shell->compositor->surface_list;
+               list = &shell->lock_layer.surface_list;
 
-       wl_list_remove(&surface->surface->link);
-       wl_list_insert(list, &surface->surface->link);
+       wl_list_remove(&surface->surface->layer_link);
+       wl_list_insert(list, &surface->surface->layer_link);
        surface->surface->output = surface->output;
        weston_surface_damage(surface->surface);
 }
@@ -915,8 +919,8 @@ show_screensaver(struct wl_shell *shell, struct shell_surface *surface)
 static void
 hide_screensaver(struct wl_shell *shell, struct shell_surface *surface)
 {
-       wl_list_remove(&surface->surface->link);
-       wl_list_init(&surface->surface->link);
+       wl_list_remove(&surface->surface->layer_link);
+       wl_list_init(&surface->surface->layer_link);
        surface->surface->output = NULL;
 }
 
@@ -937,7 +941,7 @@ desktop_shell_set_background(struct wl_client *client,
        wl_list_for_each(priv, &shell->backgrounds, link) {
                if (priv->output == output_resource->data) {
                        priv->surface->output = NULL;
-                       wl_list_remove(&priv->surface->link);
+                       wl_list_remove(&priv->surface->layer_link);
                        wl_list_remove(&priv->link);
                        break;
                }
@@ -975,7 +979,7 @@ desktop_shell_set_panel(struct wl_client *client,
        wl_list_for_each(priv, &shell->panels, link) {
                if (priv->output == output_resource->data) {
                        priv->surface->output = NULL;
-                       wl_list_remove(&priv->surface->link);
+                       wl_list_remove(&priv->surface->layer_link);
                        wl_list_remove(&priv->link);
                        break;
                }
@@ -1035,8 +1039,6 @@ desktop_shell_set_lock_surface(struct wl_client *client,
 static void
 resume_desktop(struct wl_shell *shell)
 {
-       struct weston_surface *surface;
-       struct wl_list *list;
        struct shell_surface *tmp;
 
        wl_list_for_each(tmp, &shell->screensaver.surfaces, link)
@@ -1044,21 +1046,12 @@ resume_desktop(struct wl_shell *shell)
 
        terminate_screensaver(shell);
 
-       wl_list_for_each(surface, &shell->hidden_surface_list, link)
-               weston_surface_assign_output(surface);
-
-       if (wl_list_empty(&shell->backgrounds)) {
-               list = &shell->compositor->surface_list;
-       } else {
-               struct shell_surface *background;
-               background = container_of(shell->backgrounds.prev,
-                                         struct shell_surface, link);
-               list = background->surface->link.prev;
-       }
-
-       if (!wl_list_empty(&shell->hidden_surface_list))
-               wl_list_insert_list(list, &shell->hidden_surface_list);
-       wl_list_init(&shell->hidden_surface_list);
+       wl_list_remove(&shell->lock_layer.link);
+       wl_list_insert(&shell->compositor->cursor_layer.link,
+                      &shell->fullscreen_layer.link);
+       wl_list_insert(&shell->fullscreen_layer.link,
+                      &shell->panel_layer.link);
+       wl_list_insert(&shell->panel_layer.link, &shell->toplevel_layer.link);
 
        shell->locked = false;
        weston_compositor_repick(shell->compositor);
@@ -1380,7 +1373,6 @@ activate(struct weston_shell *base, struct weston_surface *es,
 {
        struct wl_shell *shell = container_of(base, struct wl_shell, shell);
        struct weston_compositor *compositor = shell->compositor;
-       struct wl_list *list;
 
        weston_surface_activate(es, device, time);
 
@@ -1389,35 +1381,23 @@ activate(struct weston_shell *base, struct weston_surface *es,
 
        switch (get_shell_surface_type(es)) {
        case SHELL_SURFACE_BACKGROUND:
-               /* put background back to bottom */
-               wl_list_remove(&es->link);
-               wl_list_insert(compositor->surface_list.prev, &es->link);
-               break;
        case SHELL_SURFACE_PANEL:
-               /* already put on top */
+       case SHELL_SURFACE_LOCK:
                break;
+
        case SHELL_SURFACE_SCREENSAVER:
                /* always below lock surface */
-               if (shell->lock_surface) {
-                       wl_list_remove(&es->link);
-                       wl_list_insert(&shell->lock_surface->surface->link,
-                                      &es->link);
-               }
+               if (shell->lock_surface)
+                       weston_surface_restack(es,
+                                              &shell->lock_surface->surface->layer_link);
                break;
        case SHELL_SURFACE_FULLSCREEN:
                /* should on top of panels */
                break;
        default:
-               if (!shell->locked) {
-                       list = weston_compositor_top(compositor);
-
-                       /* bring panel back to top */
-                       struct shell_surface *panel;
-                       wl_list_for_each(panel, &shell->panels, link) {
-                               wl_list_remove(&panel->surface->link);
-                               wl_list_insert(list, &panel->surface->link);
-                       }
-               }
+               weston_surface_restack(es,
+                                      &shell->toplevel_layer.surface_list);
+               break;
        }
 }
 
@@ -1448,9 +1428,6 @@ static void
 lock(struct weston_shell *base)
 {
        struct wl_shell *shell = container_of(base, struct wl_shell, shell);
-       struct wl_list *surface_list = &shell->compositor->surface_list;
-       struct weston_surface *cur;
-       struct weston_surface *tmp;
        struct weston_input_device *device;
        struct shell_surface *shsurf;
        struct weston_output *output;
@@ -1466,28 +1443,15 @@ lock(struct weston_shell *base)
 
        shell->locked = true;
 
-       /* Move all surfaces from compositor's list to our hidden list,
-        * except the background. This way nothing else can show or
-        * receive input events while we are locked. */
+       /* Hide all surfaces by removing the fullscreen, panel and
+        * toplevel layers.  This way nothing else can show or receive
+        * input events while we are locked. */
 
-       if (!wl_list_empty(&shell->hidden_surface_list)) {
-               fprintf(stderr,
-               "%s: Assertion failed: hidden_surface_list is not empty.\n",
-                                                               __func__);
-       }
-
-       wl_list_for_each_safe(cur, tmp, surface_list, link) {
-               /* skip input device sprites, cur->surface is uninitialised */
-               if (cur->surface.resource.client == NULL)
-                       continue;
-
-               if (get_shell_surface_type(cur) == SHELL_SURFACE_BACKGROUND)
-                       continue;
-
-               cur->output = NULL;
-               wl_list_remove(&cur->link);
-               wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
-       }
+       wl_list_remove(&shell->panel_layer.link);
+       wl_list_remove(&shell->toplevel_layer.link);
+       wl_list_remove(&shell->fullscreen_layer.link);
+       wl_list_insert(&shell->compositor->cursor_layer.link,
+                      &shell->lock_layer.link);
 
        launch_screensaver(shell);
 
@@ -1555,24 +1519,14 @@ map(struct weston_shell *base, struct weston_surface *surface,
 {
        struct wl_shell *shell = container_of(base, struct wl_shell, shell);
        struct weston_compositor *compositor = shell->compositor;
-       struct wl_list *list;
        struct shell_surface *shsurf;
        enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
-       int do_configure;
        int panel_height = 0;
 
        shsurf = get_shell_surface(surface);
        if (shsurf)
                surface_type = shsurf->type;
 
-       if (shell->locked) {
-               list = &shell->hidden_surface_list;
-               do_configure = 0;
-       } else {
-               list = weston_compositor_top(compositor);
-               do_configure = 1;
-       }
-
        surface->geometry.width = width;
        surface->geometry.height = height;
        surface->geometry.dirty = 1;
@@ -1615,19 +1569,19 @@ map(struct weston_shell *base, struct weston_surface *surface,
        switch (surface_type) {
        case SHELL_SURFACE_BACKGROUND:
                /* background always visible, at the bottom */
-               wl_list_insert(compositor->surface_list.prev, &surface->link);
-               do_configure = 1;
+               wl_list_insert(&shell->background_layer.surface_list,
+                              &surface->layer_link);
                break;
        case SHELL_SURFACE_PANEL:
                /* panel always on top, hidden while locked */
-               wl_list_insert(list, &surface->link);
+               wl_list_insert(&shell->panel_layer.surface_list,
+                              &surface->layer_link);
                break;
        case SHELL_SURFACE_LOCK:
                /* lock surface always visible, on top */
-               wl_list_insert(&compositor->surface_list, &surface->link);
-
+               wl_list_insert(&shell->lock_layer.surface_list,
+                              &surface->layer_link);
                weston_compositor_wake(compositor);
-               do_configure = 1;
                break;
        case SHELL_SURFACE_SCREENSAVER:
                /* If locked, show it. */
@@ -1638,32 +1592,20 @@ map(struct weston_shell *base, struct weston_surface *surface,
                        if (!shell->lock_surface)
                                compositor->state = WESTON_COMPOSITOR_IDLE;
                }
-               do_configure = 0;
                break;
        case SHELL_SURFACE_FULLSCREEN:
-               do_configure = 1;
-               break;
        case SHELL_SURFACE_NONE:
-               do_configure = 0;
                break;
        default:
-               /* everything else just below the panel */
-               if (!wl_list_empty(&shell->panels)) {
-                       struct shell_surface *panel =
-                               container_of(shell->panels.prev,
-                                            struct shell_surface, link);
-                       wl_list_insert(&panel->surface->link, &surface->link);
-               } else {
-                       wl_list_insert(list, &surface->link);
-               }
+               wl_list_insert(&shell->toplevel_layer.surface_list,
+                              &surface->layer_link); 
+               break;
        }
 
-       if (do_configure) {
-               weston_surface_assign_output(surface);
-               weston_compositor_repick(compositor);
-               if (surface_type == SHELL_SURFACE_MAXIMIZED)
-                       surface->output = shsurf->output;
-       }
+       weston_surface_assign_output(surface);
+       weston_compositor_repick(compositor);
+       if (surface_type == SHELL_SURFACE_MAXIMIZED)
+               surface->output = shsurf->output;
 
        switch (surface_type) {
        case SHELL_SURFACE_TOPLEVEL:
@@ -2054,11 +1996,17 @@ shell_init(struct weston_compositor *ec)
        shell->shell.configure = configure;
        shell->shell.destroy = shell_destroy;
 
-       wl_list_init(&shell->hidden_surface_list);
        wl_list_init(&shell->backgrounds);
        wl_list_init(&shell->panels);
        wl_list_init(&shell->screensaver.surfaces);
 
+       weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
+       weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
+       weston_layer_init(&shell->toplevel_layer, &shell->panel_layer.link);
+       weston_layer_init(&shell->background_layer,
+                         &shell->toplevel_layer.link);
+       wl_list_init(&shell->lock_layer.surface_list);
+
        shell_configuration(shell);
 
        if (wl_display_add_global(ec->wl_display, &wl_shell_interface,