[PATCH weston 09/11] shell: Manage toplevel surfaces on all workspaces in one list
Jonas Ådahl
jadahl at gmail.com
Sat Jan 26 06:33:39 PST 2013
Instead of linking and unlinking per-workspace layers to the output
cycle, keep all toplevel surfaces in one per-shell list. Shell surfaces
now has a visibility flag, and surfaces that has visibility set to true
will be added to a reintroduced toplevel layer.
Changing active workspace corresponds to updating the visibility flag
and marking the toplevel layer as dirty. Before an output repaint, if
the toplevel has been marked as dirty, the shell will repopulate the
toplevel surface with visible surfaces.
Structuring surfaces this way as the benefit of simple stacking order
across outputs.
Black surfaces are currently managed as a special case, stacked on the
toplevel layer beneath a fullscreen surface in the pre output repaint
hook.
Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
src/compositor.c | 3 +
src/compositor.h | 2 +
src/shell.c | 286 +++++++++++++++++++++++++++++++++++-------------------
3 files changed, 190 insertions(+), 101 deletions(-)
diff --git a/src/compositor.c b/src/compositor.c
index 7aba77d..f8b2400 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1055,6 +1055,8 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
weston_compositor_update_drag_surfaces(ec);
+ wl_signal_emit(&ec->pre_output_repaint_signal, output);
+
/* Rebuild the surface list and update surface transforms up front. */
wl_list_init(&ec->surface_list);
wl_list_init(&frame_callback_list);
@@ -2965,6 +2967,7 @@ weston_compositor_init(struct weston_compositor *ec,
wl_signal_init(&ec->kill_signal);
wl_signal_init(&ec->lock_signal);
wl_signal_init(&ec->unlock_signal);
+ wl_signal_init(&ec->pre_output_repaint_signal);
wl_signal_init(&ec->show_input_panel_signal);
wl_signal_init(&ec->hide_input_panel_signal);
wl_signal_init(&ec->seat_created_signal);
diff --git a/src/compositor.h b/src/compositor.h
index 041f910..9a336d2 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -287,6 +287,8 @@ struct weston_compositor {
struct wl_signal lock_signal;
struct wl_signal unlock_signal;
+ struct wl_signal pre_output_repaint_signal;
+
struct wl_signal show_input_panel_signal;
struct wl_signal hide_input_panel_signal;
diff --git a/src/shell.c b/src/shell.c
index c8ab636..ad5800d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -63,6 +63,7 @@ struct workspace_container {
unsigned int current;
unsigned int num;
+ struct desktop_shell *shell;
struct weston_output *output;
struct weston_animation animation;
@@ -75,11 +76,11 @@ struct workspace_container {
};
struct workspace {
- struct weston_layer layer;
-
struct workspace_container *container;
struct wl_list focus_list;
struct wl_listener seat_destroyed_listener;
+
+ bool visible;
};
struct input_panel_surface {
@@ -94,11 +95,13 @@ struct desktop_shell {
struct wl_listener lock_listener;
struct wl_listener unlock_listener;
struct wl_listener destroy_listener;
+ struct wl_listener pre_output_repaint_listener;
struct wl_listener show_input_panel_listener;
struct wl_listener hide_input_panel_listener;
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 weston_layer input_panel_layer;
@@ -124,6 +127,9 @@ struct desktop_shell {
struct wl_listener output_create_listener;
+ struct wl_list toplevel_surface_list;
+ bool stack_dirty;
+
struct {
struct hash_table *table;
unsigned int default_num;
@@ -412,20 +418,23 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
struct focus_state,
surface_destroy_listener);
struct desktop_shell *shell;
- struct weston_surface *surface, *next;
+ struct shell_surface *shsurf, *next;
next = NULL;
- wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
- if (surface == state->keyboard_focus)
+ wl_list_for_each(shsurf,
+ &state->ws->container->shell->toplevel_surface_list,
+ link) {
+ if (shsurf->surface == state->keyboard_focus ||
+ shsurf->workspace->visible)
continue;
- next = surface;
+ next = shsurf;
break;
}
if (next) {
shell = state->seat->compositor->shell_interface.shell;
- activate(shell, next, state->seat);
+ activate(shell, next->surface, state->seat);
} else {
wl_list_remove(&state->link);
focus_state_destroy(state);
@@ -538,6 +547,15 @@ seat_destroyed(struct wl_listener *listener, void *data)
wl_list_remove(&state->link);
}
+static void
+workspace_set_visible(struct workspace *ws, bool visible)
+{
+ if (ws->visible != visible) {
+ ws->visible = visible;
+ ws->container->shell->stack_dirty = true;
+ }
+}
+
static struct workspace *
workspace_create(struct workspace_container *container)
{
@@ -545,36 +563,54 @@ workspace_create(struct workspace_container *container)
if (ws == NULL)
return NULL;
- weston_layer_init(&ws->layer, NULL);
-
ws->container = container;
wl_list_init(&ws->focus_list);
wl_list_init(&ws->seat_destroyed_listener.link);
ws->seat_destroyed_listener.notify = seat_destroyed;
+ ws->visible = false;
+
return ws;
}
static int
workspace_is_empty(struct workspace *ws)
{
- return wl_list_empty(&ws->layer.surface_list);
+ struct desktop_shell *shell = ws->container->shell;
+ struct shell_surface *shsurf;
+
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link)
+ if (ws == shsurf->workspace)
+ return false;
+ return true;
}
static void
-workspace_stack_surface(struct workspace *ws, struct shell_surface *shsurf)
+workspace_stack_surface_above(struct workspace *ws, struct wl_list *below,
+ struct shell_surface *shsurf)
{
- wl_list_insert(&ws->layer.surface_list,
- &shsurf->surface->layer_link);
+ struct desktop_shell *shell = shsurf->shell;
+
+ wl_list_insert(below, &shsurf->link);
+ shell->stack_dirty = true;
shsurf->workspace = ws;
}
static void
+workspace_stack_surface(struct workspace *ws, struct shell_surface *shsurf)
+{
+ struct desktop_shell *shell = shsurf->shell;
+
+ workspace_stack_surface_above(ws, &shell->toplevel_surface_list,
+ shsurf);
+}
+
+static void
workspace_restack_surface(struct workspace *ws, struct shell_surface *shsurf)
{
struct weston_surface *surface = shsurf->surface;
- wl_list_remove(&surface->layer_link);
+ wl_list_remove(&shsurf->link);
workspace_stack_surface(ws, shsurf);
weston_surface_damage_below(surface);
weston_surface_damage(surface);
@@ -635,14 +671,16 @@ get_workspace_container(struct desktop_shell *shell, uint32_t container_id)
}
static struct workspace *
-find_workspace_for(struct desktop_shell *shell, struct weston_surface *surface)
+find_workspace_for(struct shell_surface *shsurf)
{
+ struct weston_surface *surface = shsurf->surface;
struct workspace_container *container;
if (surface->output)
- container = get_workspace_container(shell, surface->output->id);
+ container = get_workspace_container(shsurf->shell,
+ surface->output->id);
else
- container = find_first_workspace_container(shell);
+ container = find_first_workspace_container(shsurf->shell);
return workspace_container_get_current(container);
}
@@ -670,6 +708,7 @@ workspace_container_create(struct desktop_shell *shell,
if (container == NULL)
return NULL;
+ container->shell = shell;
container->output = output;
container->current = 0;
container->num = num;
@@ -702,9 +741,9 @@ get_output_height(struct weston_output *output)
}
static void
-surface_translate(struct weston_surface *surface, double d)
+surface_translate(struct shell_surface *shsurf, double d)
{
- struct shell_surface *shsurf = get_shell_surface(surface);
+ struct weston_surface *surface = shsurf->surface;
struct weston_transform *transform;
transform = &shsurf->workspace_transform;
@@ -721,34 +760,42 @@ surface_translate(struct weston_surface *surface, double d)
static void
workspace_translate_out(struct workspace *ws, double fraction)
{
- struct weston_surface *surface;
+ struct desktop_shell *shell = ws->container->shell;
+ struct shell_surface *shsurf;
unsigned int height;
double d;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- height = get_output_height(surface->output);
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ if (shsurf->workspace != ws)
+ continue;
+
+ height = get_output_height(shsurf->surface->output);
d = height * fraction;
- surface_translate(surface, d);
+ surface_translate(shsurf, d);
}
}
static void
workspace_translate_in(struct workspace *ws, double fraction)
{
- struct weston_surface *surface;
+ struct desktop_shell *shell = ws->container->shell;
+ struct shell_surface *shsurf;
unsigned int height;
double d;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- height = get_output_height(surface->output);
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ if (shsurf->workspace != ws)
+ continue;
+
+ height = get_output_height(shsurf->surface->output);
if (fraction > 0)
d = -(height - height * fraction);
else
d = height + height * fraction;
- surface_translate(surface, d);
+ surface_translate(shsurf, d);
}
}
@@ -785,11 +832,13 @@ reverse_workspace_change_animation(struct desktop_shell *shell,
static void
workspace_deactivate_transforms(struct workspace *ws)
{
- struct weston_surface *surface;
+ struct desktop_shell *shell = ws->container->shell;
struct shell_surface *shsurf;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- shsurf = get_shell_surface(surface);
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ if (shsurf->workspace != ws)
+ continue;
+
if (!wl_list_empty(&shsurf->workspace_transform.link)) {
wl_list_remove(&shsurf->workspace_transform.link);
wl_list_init(&shsurf->workspace_transform.link);
@@ -811,7 +860,7 @@ finish_workspace_change_animation(struct desktop_shell *shell,
workspace_deactivate_transforms(to);
container->anim_to = NULL;
- wl_list_remove(&container->anim_from->layer.link);
+ workspace_set_visible(container->anim_from, false);
}
static void
@@ -894,7 +943,7 @@ animate_workspace_change(struct desktop_shell *shell,
wl_list_insert(&container->output->animation_list,
&container->animation.link);
- wl_list_insert(from->layer.link.prev, &to->layer.link);
+ workspace_set_visible(to, true);
workspace_translate_in(to, 0);
@@ -910,8 +959,8 @@ update_workspace(struct workspace_container *container,
struct workspace *to)
{
container->current = index;
- wl_list_insert(&from->layer.link, &to->layer.link);
- wl_list_remove(&from->layer.link);
+ workspace_set_visible(from, false);
+ workspace_set_visible(to, true);
}
static void
@@ -959,18 +1008,19 @@ change_workspace(struct desktop_shell *shell,
static bool
workspace_has_only(struct workspace *ws, struct weston_surface *surface)
{
- struct wl_list *list = &ws->layer.surface_list;
- struct wl_list *e;
-
- if (wl_list_empty(list))
- return false;
-
- e = list->next;
+ struct desktop_shell *shell = ws->container->shell;
+ struct shell_surface *shsurf;
+ bool found = false;
- if (e->next != list)
- return false;
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ if (ws == shsurf->workspace) {
+ if (found)
+ return false;
+ found = true;
+ }
+ }
- return container_of(e, struct weston_surface, layer_link) == surface;
+ return found;
}
static void
@@ -1035,9 +1085,6 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
if (container->anim_from == to &&
container->anim_to == from) {
- wl_list_remove(&to->layer.link);
- wl_list_insert(from->layer.link.prev, &to->layer.link);
-
reverse_workspace_change_animation(shell, container, index,
from, to);
broadcast_current_workspace_state(shell);
@@ -1612,7 +1659,8 @@ shell_unset_fullscreen(struct shell_surface *shsurf)
shsurf->saved_rotation_valid = false;
}
- ws = find_workspace_for(shsurf->shell, shsurf->surface);
+ wl_list_remove(&shsurf->surface->layer_link);
+ ws = find_workspace_for(shsurf);
workspace_restack_surface(ws, shsurf);
}
@@ -1896,6 +1944,10 @@ shell_stack_fullscreen(struct shell_surface *shsurf)
&surface->layer_link);
weston_surface_damage(surface);
+ wl_list_remove(&shsurf->link);
+ wl_list_init(&shsurf->link);
+ shsurf->workspace = NULL;
+
if (!shsurf->fullscreen.black_surface)
shsurf->fullscreen.black_surface =
create_black_surface(surface->compositor,
@@ -2430,10 +2482,6 @@ restore_current_focus_state(void *element, void *data)
static void
resume_desktop(struct desktop_shell *shell)
{
- struct weston_output *output;
- struct workspace_container *container;
- struct workspace *ws;
-
terminate_screensaver(shell);
wl_list_remove(&shell->lock_layer.link);
@@ -2441,12 +2489,8 @@ resume_desktop(struct desktop_shell *shell)
&shell->fullscreen_layer.link);
wl_list_insert(&shell->fullscreen_layer.link,
&shell->panel_layer.link);
-
- wl_list_for_each(output, &shell->compositor->output_list, link) {
- container = get_workspace_container(shell, output->id);
- ws = workspace_container_get_current(container);
- wl_list_insert(shell->panel_layer.link.prev, &ws->layer.link);
- }
+ wl_list_insert(&shell->panel_layer.link,
+ &shell->toplevel_layer.link);
if (shell->showing_input_panels)
wl_list_insert(&shell->panel_layer.link,
@@ -2809,13 +2853,12 @@ lower_fullscreen_layer(struct desktop_shell *shell)
wl_list_for_each_reverse_safe(surface, prev,
&shell->fullscreen_layer.surface_list,
layer_link) {
- ws = find_workspace_for(shell, surface);
shsurf = get_shell_surface(surface);
- if (shsurf)
+ if (shsurf) {
+ wl_list_remove(&surface->layer_link);
+ ws = find_workspace_for(shsurf);
workspace_restack_surface(ws, shsurf);
- else
- weston_surface_restack(surface,
- &ws->layer.surface_list);
+ }
}
}
@@ -2829,7 +2872,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
weston_surface_activate(es, seat);
- ws = find_workspace_for(shell, es);
+ ws = find_workspace_for(shsurf);
state = ensure_focus_state(shell, ws, seat);
if (state == NULL)
return;
@@ -2892,15 +2935,6 @@ click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
}
static void
-unlink_current_workspace(void *element, void *data)
-{
- struct workspace_container *container = element;
- struct workspace *ws = workspace_container_get_current(container);
-
- wl_list_remove(&ws->layer.link);
-}
-
-static void
lock(struct wl_listener *listener, void *data)
{
struct desktop_shell *shell =
@@ -2921,12 +2955,11 @@ lock(struct wl_listener *listener, void *data)
* toplevel layers. This way nothing else can show or receive
* input events while we are locked. */
+ wl_list_remove(&shell->toplevel_layer.link);
wl_list_remove(&shell->panel_layer.link);
wl_list_remove(&shell->fullscreen_layer.link);
if (shell->showing_input_panels)
wl_list_remove(&shell->input_panel_layer.link);
- hash_table_for_each(shell->workspaces.table,
- unlink_current_workspace, NULL);
wl_list_insert(&shell->compositor->cursor_layer.link,
&shell->lock_layer.link);
@@ -2962,6 +2995,44 @@ unlock(struct wl_listener *listener, void *data)
}
static void
+pre_output_repaint(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell = container_of(listener,
+ struct desktop_shell,
+ pre_output_repaint_listener);
+ struct weston_surface *surface, *next;
+ struct weston_surface *black_surface;
+ struct shell_surface *shsurf;
+ struct weston_layer *toplevel_layer = &shell->toplevel_layer;
+
+ if (!shell->stack_dirty)
+ return;
+
+ shell->stack_dirty = false;
+
+ wl_list_for_each_safe(surface, next,
+ &shell->toplevel_layer.surface_list,
+ layer_link) {
+ wl_list_remove(&surface->layer_link);
+ wl_list_init(&surface->layer_link);
+ }
+
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ if (shsurf->workspace->visible) {
+ wl_list_insert(toplevel_layer->surface_list.prev,
+ &shsurf->surface->layer_link);
+
+ black_surface = shsurf->fullscreen.black_surface;
+ if (black_surface) {
+ wl_list_remove(&black_surface->layer_link);
+ wl_list_insert(&shsurf->surface->layer_link,
+ &black_surface->layer_link);
+ }
+ }
+ }
+}
+
+static void
show_input_panels(struct wl_listener *listener, void *data)
{
struct desktop_shell *shell =
@@ -3089,6 +3160,7 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
struct shell_surface *shsurf = get_shell_surface(surface);
enum shell_surface_type surface_type = shsurf->type;
struct weston_surface *parent;
+ struct shell_surface *parent_shsurf;
struct weston_seat *seat;
struct workspace_container *container;
struct workspace *ws;
@@ -3130,7 +3202,16 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
case SHELL_SURFACE_POPUP:
case SHELL_SURFACE_TRANSIENT:
parent = shsurf->parent;
- wl_list_insert(parent->layer_link.prev, &surface->layer_link);
+ parent_shsurf = get_shell_surface(parent);
+
+ if (parent_shsurf && parent_shsurf->workspace) {
+ workspace_stack_surface_above(parent_shsurf->workspace,
+ parent_shsurf->link.prev,
+ shsurf);
+ } else {
+ wl_list_insert(parent->layer_link.prev,
+ &shsurf->surface->layer_link);
+ }
break;
case SHELL_SURFACE_FULLSCREEN:
case SHELL_SURFACE_NONE:
@@ -3523,18 +3604,15 @@ static void
switcher_next(struct switcher *switcher)
{
struct desktop_shell *shell = switcher->shell;
- struct weston_output *output;
- struct workspace_container *container;
- struct workspace *ws;
struct weston_surface *surface;
struct weston_surface *first = NULL, *prev = NULL, *next = NULL;
struct shell_surface *shsurf;
+ struct weston_surface *black_surface;
- wl_list_for_each(output, &shell->compositor->output_list, link) {
- container = get_workspace_container(shell, output->id);
- ws = workspace_container_get_current(container);
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ surface = shsurf->surface;
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+ if (shsurf->workspace->visible) {
switch (get_shell_surface_type(surface)) {
case SHELL_SURFACE_TOPLEVEL:
case SHELL_SURFACE_FULLSCREEN:
@@ -3552,10 +3630,11 @@ switcher_next(struct switcher *switcher)
break;
}
- if (is_black_surface(surface, NULL)) {
- surface->alpha = 0.25;
- surface->geometry.dirty = 1;
- weston_surface_damage(surface);
+ black_surface = shsurf->fullscreen.black_surface;
+ if (black_surface) {
+ black_surface->alpha = 0.25;
+ black_surface->geometry.dirty = 1;
+ weston_surface_damage(black_surface);
}
}
}
@@ -3591,19 +3670,19 @@ static void
switcher_destroy(struct switcher *switcher)
{
struct desktop_shell *shell = switcher->shell;
- struct weston_surface *surface;
+ struct shell_surface *shsurf;
+ struct weston_surface *black_surface;
struct wl_keyboard *keyboard = switcher->grab.keyboard;
- struct weston_output *output;
- struct workspace_container *container;
- struct workspace *ws;
- wl_list_for_each(output, &shell->compositor->output_list, link) {
- container = get_workspace_container(shell, output->id);
- ws = workspace_container_get_current(container);
+ wl_list_for_each(shsurf, &shell->toplevel_surface_list, link) {
+ shsurf->surface->alpha = 1.0;
+ weston_surface_damage(shsurf->surface);
- wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
- surface->alpha = 1.0;
- weston_surface_damage(surface);
+ black_surface = shsurf->fullscreen.black_surface;
+ if (black_surface) {
+ black_surface->alpha = 0.25;
+ black_surface->geometry.dirty = 1;
+ weston_surface_damage(black_surface);
}
}
@@ -3963,7 +4042,6 @@ init_output_workspaces(struct desktop_shell *shell,
struct weston_output *output)
{
struct workspace_container *container;
- struct workspace *ws;
container = workspace_container_create(shell,
output,
@@ -3977,8 +4055,7 @@ init_output_workspaces(struct desktop_shell *shell,
return -1;
}
- ws = workspace_container_get_current(container);
- wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
+ workspace_set_visible(workspace_container_get_current(container), true);
return 0;
}
@@ -4106,6 +4183,9 @@ module_init(struct weston_compositor *ec)
memset(shell, 0, sizeof *shell);
shell->compositor = ec;
+ wl_list_init(&shell->toplevel_surface_list);
+ shell->stack_dirty = false;
+
shell->workspaces.table = hash_table_create();
if (shell->workspaces.table == NULL) {
free(shell);
@@ -4118,6 +4198,9 @@ module_init(struct weston_compositor *ec)
wl_signal_add(&ec->lock_signal, &shell->lock_listener);
shell->unlock_listener.notify = unlock;
wl_signal_add(&ec->unlock_signal, &shell->unlock_listener);
+ shell->pre_output_repaint_listener.notify = pre_output_repaint;
+ wl_signal_add(&ec->pre_output_repaint_signal,
+ &shell->pre_output_repaint_listener);
shell->show_input_panel_listener.notify = show_input_panels;
wl_signal_add(&ec->show_input_panel_signal, &shell->show_input_panel_listener);
shell->hide_input_panel_listener.notify = hide_input_panels;
@@ -4138,7 +4221,8 @@ module_init(struct weston_compositor *ec)
weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
- weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
+ weston_layer_init(&shell->toplevel_layer, &shell->panel_layer.link);
+ weston_layer_init(&shell->background_layer, &shell->toplevel_layer.link);
weston_layer_init(&shell->lock_layer, NULL);
weston_layer_init(&shell->input_panel_layer, NULL);
--
1.7.10.4
More information about the wayland-devel
mailing list