[PATCH weston 3/6] shell: Add possibility to move surfaces to other workspaces
Jonas Ådahl
jadahl at gmail.com
Wed Aug 29 13:13:00 PDT 2012
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 at gmail.com>
---
src/shell.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 150 insertions(+), 11 deletions(-)
diff --git a/src/shell.c b/src/shell.c
index b37ea25..930159a 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -109,6 +109,7 @@ struct desktop_shell {
unsigned int num;
struct weston_animation animation;
+ struct wl_list anim_sticky_list;
int anim_dir;
uint32_t anim_timestamp;
double anim_current;
@@ -450,6 +451,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
workspace_destroy(struct workspace *ws)
{
struct focus_state *state, *next;
@@ -591,8 +620,6 @@ reverse_workspace_change_animation(struct desktop_shell *shell,
shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
shell->workspaces.anim_timestamp = 0;
- restore_focus_state(shell, to);
-
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) {
shsurf = get_shell_surface(surface);
- wl_list_remove(&shsurf->workspace_transform.link);
- wl_list_init(&shsurf->workspace_transform.link);
+ if (!wl_list_empty(&shsurf->workspace_transform.link)) {
+ wl_list_remove(&shsurf->workspace_transform.link);
+ wl_list_init(&shsurf->workspace_transform.link);
+ }
shsurf->surface->geometry.dirty = 1;
}
}
@@ -704,7 +733,7 @@ animate_workspace_change(struct desktop_shell *shell,
wl_list_insert(&output->animation_list,
&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);
@@ -714,6 +743,15 @@ animate_workspace_change(struct desktop_shell *shell,
}
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
change_workspace(struct desktop_shell *shell, unsigned int index)
{
struct workspace *from;
@@ -731,6 +769,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
if (shell->workspaces.anim_from == to &&
shell->workspaces.anim_to == from) {
+ restore_focus_state(shell, to);
reverse_workspace_change_animation(shell, index, from, to);
return;
}
@@ -740,17 +779,79 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
shell->workspaces.anim_from,
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
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
noop_grab_focus(struct wl_pointer_grab *grab,
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
@@ -3335,6 +3436,37 @@ workspace_f_binding(struct wl_seat *seat, uint32_t time,
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
shell_destroy(struct wl_listener *listener, void *data)
@@ -3409,6 +3541,12 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
workspace_up_binding, shell);
weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
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. */
if (shell->workspaces.num > 1) {
@@ -3482,6 +3620,7 @@ shell_init(struct weston_compositor *ec)
}
activate_workspace(shell, 0);
+ wl_list_init(&shell->workspaces.anim_sticky_list);
wl_list_init(&shell->workspaces.animation.link);
shell->workspaces.animation.frame = animate_workspace_change_frame;
--
1.7.9.5
More information about the wayland-devel
mailing list