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>
This commit is contained in:
committed by
Kristian Høgsberg
parent
568994400b
commit
8de6a1ddae
+150
-11
@@ -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);
|
||||||
wl_list_remove(&shsurf->workspace_transform.link);
|
if (!wl_list_empty(&shsurf->workspace_transform.link)) {
|
||||||
wl_list_init(&shsurf->workspace_transform.link);
|
wl_list_remove(&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)) {
|
restore_focus_state(shell, to);
|
||||||
shell->workspaces.current = index;
|
|
||||||
wl_list_insert(&from->layer.link, &to->layer.link);
|
|
||||||
wl_list_remove(&from->layer.link);
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user