mirror of
https://gitlab.freedesktop.org/wayland/weston
synced 2024-09-06 09:56:14 +00:00
shell: Virtual workspaces
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, modifier - Down, modifier - F1 up to F6) are used for navigating between workspaces. By default a single workspace is created. Surfaces of inactive workspaces have their outputs NULL:ed so that frame callbacks gets queued instead of emitted. When workspace gets visible again surface's outputs are assigned. Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
parent
db7737609c
commit
e3cddce5a6
|
@ -1125,6 +1125,7 @@ WL_EXPORT void
|
|||
weston_layer_init(struct weston_layer *layer, struct wl_list *below)
|
||||
{
|
||||
wl_list_init(&layer->surface_list);
|
||||
if (below != NULL)
|
||||
wl_list_insert(below, &layer->link);
|
||||
}
|
||||
|
||||
|
|
200
src/shell.c
200
src/shell.c
|
@ -38,6 +38,8 @@
|
|||
#include "../shared/config-parser.h"
|
||||
#include "log.h"
|
||||
|
||||
#define DEFAULT_NUM_WORKSPACES 1
|
||||
|
||||
enum animation_type {
|
||||
ANIMATION_NONE,
|
||||
|
||||
|
@ -45,6 +47,10 @@ enum animation_type {
|
|||
ANIMATION_FADE
|
||||
};
|
||||
|
||||
struct workspace {
|
||||
struct weston_layer layer;
|
||||
};
|
||||
|
||||
struct desktop_shell {
|
||||
struct weston_compositor *compositor;
|
||||
|
||||
|
@ -54,7 +60,6 @@ struct desktop_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;
|
||||
|
||||
|
@ -79,6 +84,12 @@ struct desktop_shell {
|
|||
struct wl_list backgrounds;
|
||||
struct wl_list panels;
|
||||
|
||||
struct {
|
||||
struct wl_array array;
|
||||
unsigned int current;
|
||||
unsigned int num;
|
||||
} workspaces;
|
||||
|
||||
struct {
|
||||
char *path;
|
||||
int duration;
|
||||
|
@ -276,12 +287,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[] = {
|
||||
|
@ -302,6 +316,79 @@ 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
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
weston_compositor_damage_all(shell->compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1540,7 +1627,6 @@ resume_desktop(struct desktop_shell *shell)
|
|||
&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;
|
||||
shell->compositor->idle_time = shell->compositor->option_idle_time;
|
||||
|
@ -1935,6 +2021,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);
|
||||
|
||||
|
@ -1956,18 +2044,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;
|
||||
}
|
||||
}
|
||||
|
@ -2033,7 +2124,6 @@ lock(struct wl_listener *listener, void *data)
|
|||
* input events while we are locked. */
|
||||
|
||||
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);
|
||||
|
@ -2101,16 +2191,13 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
|
|||
int32_t width, int32_t height, int32_t sx, int32_t sy)
|
||||
{
|
||||
struct weston_compositor *compositor = shell->compositor;
|
||||
struct shell_surface *shsurf;
|
||||
enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
|
||||
struct shell_surface *shsurf = get_shell_surface(surface);
|
||||
enum shell_surface_type surface_type = shsurf->type;
|
||||
struct weston_surface *parent;
|
||||
struct weston_seat *seat;
|
||||
struct workspace *ws;
|
||||
int panel_height = 0;
|
||||
|
||||
shsurf = get_shell_surface(surface);
|
||||
if (shsurf)
|
||||
surface_type = shsurf->type;
|
||||
|
||||
surface->geometry.width = width;
|
||||
surface->geometry.height = height;
|
||||
surface->geometry.dirty = 1;
|
||||
|
@ -2184,8 +2271,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;
|
||||
}
|
||||
|
||||
|
@ -2661,11 +2748,53 @@ force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
|
|||
kill(pid, SIGKILL);
|
||||
}
|
||||
|
||||
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--;
|
||||
|
||||
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
|
||||
workspace_f_binding(struct wl_seat *seat, uint32_t time,
|
||||
uint32_t key, void *data)
|
||||
{
|
||||
struct desktop_shell *shell = data;
|
||||
unsigned int new_index;
|
||||
|
||||
new_index = key - KEY_F1;
|
||||
if (new_index >= shell->workspaces.num)
|
||||
new_index = shell->workspaces.num - 1;
|
||||
|
||||
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);
|
||||
|
@ -2673,6 +2802,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);
|
||||
}
|
||||
|
@ -2681,6 +2814,7 @@ static void
|
|||
shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
|
||||
{
|
||||
uint32_t mod;
|
||||
int i, num_workspace_bindings;
|
||||
|
||||
/* fixed bindings */
|
||||
weston_compositor_add_key_binding(ec, KEY_BACKSPACE,
|
||||
|
@ -2722,6 +2856,21 @@ 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);
|
||||
|
||||
/* Add bindings for mod+F[1-6] for workspace 1 to 6. */
|
||||
if (shell->workspaces.num > 1) {
|
||||
num_workspace_bindings = shell->workspaces.num;
|
||||
if (num_workspace_bindings > 6)
|
||||
num_workspace_bindings = 6;
|
||||
for (i = 0; i < num_workspace_bindings; i++)
|
||||
weston_compositor_add_key_binding(ec, KEY_F1 + i, mod,
|
||||
workspace_f_binding,
|
||||
shell);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -2731,6 +2880,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)
|
||||
|
@ -2758,13 +2909,24 @@ shell_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->toplevel_layer, &shell->panel_layer.link);
|
||||
weston_layer_init(&shell->background_layer,
|
||||
&shell->toplevel_layer.link);
|
||||
wl_list_init(&shell->lock_layer.surface_list);
|
||||
weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
|
||||
weston_layer_init(&shell->lock_layer, NULL);
|
||||
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue