shell: Add possibility to move surfaces to other workspaces

By default, Control + Shift + Up/Down will move the currently active
surface, if any, while changing to another workspace.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
Jonas Ådahl 12 years ago committed by Kristian Høgsberg
parent 568994400b
commit 8de6a1ddae
  1. 157
      src/shell.c

@ -109,6 +109,7 @@ struct desktop_shell {
unsigned int num; unsigned int num;
struct weston_animation animation; struct weston_animation animation;
struct wl_list anim_sticky_list;
int anim_dir; int anim_dir;
uint32_t anim_timestamp; uint32_t anim_timestamp;
double anim_current; double anim_current;
@ -449,6 +450,34 @@ restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
} }
} }
static void
replace_focus_state(struct desktop_shell *shell, struct workspace *ws,
struct weston_seat *seat)
{
struct focus_state *state;
struct wl_surface *surface;
wl_list_for_each(state, &ws->focus_list, link) {
if (state->seat == seat) {
surface = seat->seat.keyboard->focus;
state->keyboard_focus =
(struct weston_surface *) surface;
return;
}
}
}
static void
drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
struct weston_surface *surface)
{
struct focus_state *state;
wl_list_for_each(state, &ws->focus_list, link)
if (state->keyboard_focus == surface)
state->keyboard_focus = NULL;
}
static void static void
workspace_destroy(struct workspace *ws) workspace_destroy(struct workspace *ws)
{ {
@ -591,8 +620,6 @@ reverse_workspace_change_animation(struct desktop_shell *shell,
shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir; shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
shell->workspaces.anim_timestamp = 0; shell->workspaces.anim_timestamp = 0;
restore_focus_state(shell, to);
weston_compositor_schedule_repaint(shell->compositor); weston_compositor_schedule_repaint(shell->compositor);
} }
@ -604,8 +631,10 @@ workspace_deactivate_transforms(struct workspace *ws)
wl_list_for_each(surface, &ws->layer.surface_list, layer_link) { wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
shsurf = get_shell_surface(surface); shsurf = get_shell_surface(surface);
if (!wl_list_empty(&shsurf->workspace_transform.link)) {
wl_list_remove(&shsurf->workspace_transform.link); wl_list_remove(&shsurf->workspace_transform.link);
wl_list_init(&shsurf->workspace_transform.link); wl_list_init(&shsurf->workspace_transform.link);
}
shsurf->surface->geometry.dirty = 1; shsurf->surface->geometry.dirty = 1;
} }
} }
@ -704,7 +733,7 @@ animate_workspace_change(struct desktop_shell *shell,
wl_list_insert(&output->animation_list, wl_list_insert(&output->animation_list,
&shell->workspaces.animation.link); &shell->workspaces.animation.link);
wl_list_insert(&from->layer.link, &to->layer.link); wl_list_insert(from->layer.link.prev, &to->layer.link);
workspace_translate_in(to, 0); workspace_translate_in(to, 0);
@ -713,6 +742,15 @@ animate_workspace_change(struct desktop_shell *shell,
weston_compositor_schedule_repaint(shell->compositor); weston_compositor_schedule_repaint(shell->compositor);
} }
static void
update_workspace(struct desktop_shell *shell, unsigned int index,
struct workspace *from, struct workspace *to)
{
shell->workspaces.current = index;
wl_list_insert(&from->layer.link, &to->layer.link);
wl_list_remove(&from->layer.link);
}
static void static void
change_workspace(struct desktop_shell *shell, unsigned int index) change_workspace(struct desktop_shell *shell, unsigned int index)
{ {
@ -731,6 +769,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
if (shell->workspaces.anim_from == to && if (shell->workspaces.anim_from == to &&
shell->workspaces.anim_to == from) { shell->workspaces.anim_to == from) {
restore_focus_state(shell, to);
reverse_workspace_change_animation(shell, index, from, to); reverse_workspace_change_animation(shell, index, from, to);
return; return;
} }
@ -740,17 +779,79 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
shell->workspaces.anim_from, shell->workspaces.anim_from,
shell->workspaces.anim_to); shell->workspaces.anim_to);
if (workspace_is_empty(to) && workspace_is_empty(from)) {
shell->workspaces.current = index;
wl_list_insert(&from->layer.link, &to->layer.link);
wl_list_remove(&from->layer.link);
restore_focus_state(shell, to); restore_focus_state(shell, to);
}
if (workspace_is_empty(to) && workspace_is_empty(from))
update_workspace(shell, index, from, to);
else else
animate_workspace_change(shell, index, from, to); animate_workspace_change(shell, index, from, to);
} }
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;
if (e->next != list)
return false;
return container_of(e, struct weston_surface, layer_link) == surface;
}
static void
take_surface_to_workspace_by_seat(struct desktop_shell *shell,
struct wl_seat *seat,
unsigned int index)
{
struct weston_surface *surface =
(struct weston_surface *) seat->keyboard->focus;
struct shell_surface *shsurf;
struct workspace *from;
struct workspace *to;
if (surface == NULL ||
index == shell->workspaces.current)
return;
from = get_current_workspace(shell);
to = get_workspace(shell, index);
wl_list_remove(&surface->layer_link);
wl_list_insert(&to->layer.surface_list, &surface->layer_link);
replace_focus_state(shell, to, (struct weston_seat *) seat);
drop_focus_state(shell, from, surface);
if (shell->workspaces.anim_from == to &&
shell->workspaces.anim_to == from) {
reverse_workspace_change_animation(shell, index, from, to);
return;
}
if (shell->workspaces.anim_to != NULL)
finish_workspace_change_animation(shell,
shell->workspaces.anim_from,
shell->workspaces.anim_to);
if (workspace_is_empty(from) &&
workspace_has_only(to, surface))
update_workspace(shell, index, from, to);
else {
shsurf = get_shell_surface(surface);
if (wl_list_empty(&shsurf->workspace_transform.link))
wl_list_insert(&shell->workspaces.anim_sticky_list,
&shsurf->workspace_transform.link);
animate_workspace_change(shell, index, from, to);
}
}
static void static void
noop_grab_focus(struct wl_pointer_grab *grab, noop_grab_focus(struct wl_pointer_grab *grab,
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
@ -3345,6 +3446,37 @@ workspace_f_binding(struct wl_seat *seat, uint32_t time,
change_workspace(shell, new_index); change_workspace(shell, new_index);
} }
static void
workspace_move_surface_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 (shell->locked)
return;
if (new_index != 0)
new_index--;
take_surface_to_workspace_by_seat(shell, seat, new_index);
}
static void
workspace_move_surface_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 (shell->locked)
return;
if (new_index < shell->workspaces.num - 1)
new_index++;
take_surface_to_workspace_by_seat(shell, seat, new_index);
}
static void static void
shell_destroy(struct wl_listener *listener, void *data) shell_destroy(struct wl_listener *listener, void *data)
@ -3421,6 +3553,12 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
workspace_up_binding, shell); workspace_up_binding, shell);
weston_compositor_add_key_binding(ec, KEY_DOWN, mod, weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
workspace_down_binding, shell); workspace_down_binding, shell);
weston_compositor_add_key_binding(ec, KEY_UP, mod | MODIFIER_SHIFT,
workspace_move_surface_up_binding,
shell);
weston_compositor_add_key_binding(ec, KEY_DOWN, mod | MODIFIER_SHIFT,
workspace_move_surface_down_binding,
shell);
/* Add bindings for mod+F[1-6] for workspace 1 to 6. */ /* Add bindings for mod+F[1-6] for workspace 1 to 6. */
if (shell->workspaces.num > 1) { if (shell->workspaces.num > 1) {
@ -3494,6 +3632,7 @@ shell_init(struct weston_compositor *ec)
} }
activate_workspace(shell, 0); activate_workspace(shell, 0);
wl_list_init(&shell->workspaces.anim_sticky_list);
wl_list_init(&shell->workspaces.animation.link); wl_list_init(&shell->workspaces.animation.link);
shell->workspaces.animation.frame = animate_workspace_change_frame; shell->workspaces.animation.frame = animate_workspace_change_frame;

Loading…
Cancel
Save