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 <[email protected]>
> ---
>  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
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to