[PATCH weston 2/3] shell: Virtual workspaces
Kristian Høgsberg
hoegsberg at gmail.com
Thu Jun 7 12:38:25 PDT 2012
On Wed, Jun 06, 2012 at 11:36:09AM +0200, Jonas Ådahl wrote:
> A workspace is a list of top level surfaces visible at a time. New
> toplevel surfaces are added to the current workspace. Default
> keybindings (modifier - Up and modifier - Down) are used for navigating
> between workspaces. By default a single workspace is created.
>
> Surfaces of inactive workspaces are hidden when changed away from the
> containing workspace so that frame callbacks gets queued instead of
> emitted. When changed back to the workspace its surfaces are again
> shown.
>
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> ---
> src/shell.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 160 insertions(+), 9 deletions(-)
>
> diff --git a/src/shell.c b/src/shell.c
> index ba421b5..56b271b 100644
> --- a/src/shell.c
> +++ b/src/shell.c
> @@ -37,6 +37,8 @@
> #include "desktop-shell-server-protocol.h"
> #include "../shared/config-parser.h"
>
> +#define DEFAULT_NUM_WORKSPACES 1
> +
> enum animation_type {
> ANIMATION_NONE,
>
> @@ -44,6 +46,10 @@ enum animation_type {
> ANIMATION_FADE
> };
>
> +struct workspace {
> + struct weston_layer layer;
> +};
> +
> struct desktop_shell {
> struct weston_compositor *compositor;
>
> @@ -79,6 +85,12 @@ struct desktop_shell {
> struct wl_list panels;
>
> struct {
> + struct wl_array array;
> + unsigned int current;
> + unsigned int num;
> + } workspaces;
> +
We use wl_list for most things and I'd prefer we do that for
workspaces too. current will be a struct workspace pointer then.
> + struct {
> char *path;
> int duration;
> struct wl_resource *binding;
> @@ -274,12 +286,15 @@ shell_configuration(struct desktop_shell *shell)
> char *config_file;
> char *path = NULL;
> int duration = 60;
> + unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
> char *modifier = NULL;
> char *win_animation = NULL;
>
> struct config_key shell_keys[] = {
> { "binding-modifier", CONFIG_KEY_STRING, &modifier },
> { "animation", CONFIG_KEY_STRING, &win_animation},
> + { "num-workspaces",
> + CONFIG_KEY_UNSIGNED_INTEGER, &num_workspaces },
> };
>
> struct config_key saver_keys[] = {
> @@ -300,6 +315,7 @@ shell_configuration(struct desktop_shell *shell)
> shell->screensaver.duration = duration;
> shell->binding_modifier = get_modifier(modifier);
> shell->win_animation_type = get_animation_type(win_animation);
> + shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
> }
>
> static void
> @@ -1586,6 +1602,85 @@ get_shell_surface_type(struct weston_surface *surface)
> }
>
> static void
> +workspace_destroy(struct workspace *ws)
> +{
> + free(ws);
> +}
> +
> +static struct workspace *
> +workspace_create(void)
> +{
> + struct workspace *ws = malloc(sizeof *ws);
> + if (ws == NULL)
> + return NULL;
> +
> + weston_layer_init(&ws->layer, NULL);
> + wl_list_init(&ws->layer.link);
> +
> + return ws;
> +}
> +
> +static struct workspace *
> +get_workspace(struct desktop_shell *shell, unsigned int index)
> +{
> + struct workspace **pws = shell->workspaces.array.data;
> + pws += index;
> + return *pws;
> +}
> +
> +static struct workspace *
> +get_current_workspace(struct desktop_shell *shell)
> +{
> + return get_workspace(shell, shell->workspaces.current);
> +}
With the changes above, these reduce to just shell->worspace.current.
> +static void
> +activate_workspace(struct desktop_shell *shell, unsigned int index)
> +{
> + struct workspace *ws;
> +
> + ws = get_workspace(shell, index);
> + wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
> +
> + shell->workspaces.current = index;
> +}
> +
> +static void
> +change_workspace(struct desktop_shell *shell, unsigned int index)
> +{
> + struct workspace *from;
> + struct workspace *to;
> + struct weston_seat *seat;
> + struct weston_surface *surface;
> +
> + if (index == shell->workspaces.current)
> + return;
> +
> + /* Don't change workspace when there is any fullscreen surfaces. */
> + if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
> + return;
> +
> + /* Clear keyboard focus so that no hidden surfaces will keep it. */
> + wl_list_for_each(seat, &shell->compositor->seat_list, link)
> + if (seat->seat.keyboard)
> + wl_keyboard_set_focus(seat->seat.keyboard, NULL);
weston_surface_unmap() does this and for pointer focus as well (but
that's more subtle since we'll repick when the pointer moves).
> + from = get_current_workspace(shell);
> + to = get_workspace(shell, index);
> +
> + shell->workspaces.current = index;
> + wl_list_insert(&from->layer.link, &to->layer.link);
> + wl_list_remove(&from->layer.link);
> +
> + wl_list_for_each(surface, &from->layer.surface_list, layer_link)
> + weston_surface_hide(surface);
> + wl_list_for_each(surface, &to->layer.surface_list, layer_link)
> + weston_surface_show(surface);
> +
> + weston_compositor_damage_all(shell->compositor);
> +}
> +
> +static void
> move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
> {
> struct weston_surface *surface =
> @@ -1933,6 +2028,8 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
> struct weston_seat *seat)
> {
> struct weston_surface *surf, *prev;
> + struct workspace *ws;
> + struct weston_layer *ws_layer;
>
> weston_surface_activate(es, seat);
>
> @@ -1954,18 +2051,21 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
> shell_configure_fullscreen(get_shell_surface(es));
> break;
> default:
> + ws = get_current_workspace(shell);
> + ws_layer = &ws->layer;
> +
> /* move the fullscreen surfaces down into the toplevel layer */
> if (!wl_list_empty(&shell->fullscreen_layer.surface_list)) {
> wl_list_for_each_reverse_safe(surf,
> prev,
> &shell->fullscreen_layer.surface_list,
> - layer_link)
> + layer_link) {
> weston_surface_restack(surf,
> - &shell->toplevel_layer.surface_list);
> + &ws_layer->surface_list);
> + }
> }
>
> - weston_surface_restack(es,
> - &shell->toplevel_layer.surface_list);
> + weston_surface_restack(es, &ws_layer->surface_list);
> break;
> }
> }
> @@ -2051,9 +2151,9 @@ lock(struct wl_listener *listener, void *data)
> weston_compositor_schedule_repaint(shell->compositor);
>
> /* reset keyboard foci */
> - wl_list_for_each(seat, &shell->compositor->seat_list, link) {
> - wl_keyboard_set_focus(seat->seat.keyboard, NULL);
> - }
> + wl_list_for_each(seat, &shell->compositor->seat_list, link)
> + if (seat->seat.keyboard)
> + wl_keyboard_set_focus(seat->seat.keyboard, NULL);
>
> /* TODO: disable bindings that should not work while locked. */
>
> @@ -2103,6 +2203,7 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
> enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
> struct weston_surface *parent;
> struct weston_seat *seat;
> + struct workspace *ws;
> int panel_height = 0;
>
> shsurf = get_shell_surface(surface);
> @@ -2182,8 +2283,8 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
> case SHELL_SURFACE_NONE:
> break;
> default:
> - wl_list_insert(&shell->toplevel_layer.surface_list,
> - &surface->layer_link);
> + ws = get_current_workspace(shell);
> + wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
> break;
> }
>
> @@ -2660,10 +2761,37 @@ force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
> }
>
> static void
> +workspace_up_binding(struct wl_seat *seat, uint32_t time,
> + uint32_t key, void *data)
> +{
> + struct desktop_shell *shell = data;
> + unsigned int new_index = shell->workspaces.current;
> +
> + if (new_index != 0)
> + new_index--;
For a wl_list, this would be
if (current->next != &shell->workspace_list)
next = container_of(current->next, struct workspace, link);
> +
> + change_workspace(shell, new_index);
> +}
> +
> +static void
> +workspace_down_binding(struct wl_seat *seat, uint32_t time,
> + uint32_t key, void *data)
> +{
> + struct desktop_shell *shell = data;
> + unsigned int new_index = shell->workspaces.current;
> +
> + if (new_index < shell->workspaces.num - 1)
> + new_index++;
> +
> + change_workspace(shell, new_index);
> +}
> +
> +static void
> shell_destroy(struct wl_listener *listener, void *data)
> {
> struct desktop_shell *shell =
> container_of(listener, struct desktop_shell, destroy_listener);
> + struct workspace **ws;
>
> if (shell->child.client)
> wl_client_destroy(shell->child.client);
> @@ -2671,6 +2799,10 @@ shell_destroy(struct wl_listener *listener, void *data)
> wl_list_remove(&shell->lock_listener.link);
> wl_list_remove(&shell->unlock_listener.link);
>
> + wl_array_for_each(ws, &shell->workspaces.array)
> + workspace_destroy(*ws);
> + wl_array_release(&shell->workspaces.array);
> +
> free(shell->screensaver.path);
> free(shell);
> }
> @@ -2720,6 +2852,10 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
> debug_repaint_binding, shell);
> weston_compositor_add_key_binding(ec, KEY_K, mod,
> force_kill_binding, shell);
> + weston_compositor_add_key_binding(ec, KEY_UP, mod,
> + workspace_up_binding, shell);
> + weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
> + workspace_down_binding, shell);
> }
>
> int
> @@ -2729,6 +2865,8 @@ WL_EXPORT int
> shell_init(struct weston_compositor *ec)
> {
> struct desktop_shell *shell;
> + struct workspace **pws;
> + unsigned int i;
>
> shell = malloc(sizeof *shell);
> if (shell == NULL)
> @@ -2761,8 +2899,21 @@ shell_init(struct weston_compositor *ec)
> &shell->toplevel_layer.link);
> wl_list_init(&shell->lock_layer.surface_list);
>
> + wl_array_init(&shell->workspaces.array);
> +
> shell_configuration(shell);
>
> + for (i = 0; i < shell->workspaces.num; i++) {
> + pws = wl_array_add(&shell->workspaces.array, sizeof *pws);
> + if (pws == NULL)
> + return -1;
> +
> + *pws = workspace_create();
> + if (*pws == NULL)
> + return -1;
> + }
> + activate_workspace(shell, 0);
> +
> if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
> shell, bind_shell) == NULL)
> return -1;
> --
> 1.7.9.5
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list