diff --git a/protocol/Makefile.am b/protocol/Makefile.am index 22cb2c9b..bf5ef990 100644 --- a/protocol/Makefile.am +++ b/protocol/Makefile.am @@ -2,5 +2,6 @@ EXTRA_DIST = \ desktop-shell.xml \ screenshooter.xml \ tablet-shell.xml \ - xserver.xml \ - text.xml + xserver.xml \ + text.xml \ + workspaces.xml diff --git a/protocol/workspaces.xml b/protocol/workspaces.xml new file mode 100644 index 00000000..22f4802b --- /dev/null +++ b/protocol/workspaces.xml @@ -0,0 +1,27 @@ + + + + + An interface for managing surfaces in workspaces. + + + + + Move the given surface to the specified workspace. + + + + + + + + The current workspace state, such as current workspace and workspace + count, has changed. + + + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index 8096849d..028735e6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,8 @@ weston_SOURCES = \ text-backend.c \ text-protocol.c \ text-server-protocol.h \ + workspaces-protocol.c \ + workspaces-server-protocol.h \ util.c \ matrix.c \ matrix.h \ @@ -173,6 +175,8 @@ BUILT_SOURCES = \ desktop-shell-server-protocol.h \ text-protocol.c \ text-server-protocol.h \ + workspaces-server-protocol.h \ + workspaces-protocol.c \ git-version.h CLEANFILES = $(BUILT_SOURCES) diff --git a/src/shell.c b/src/shell.c index 12130149..20bc355f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -35,6 +35,7 @@ #include #include "compositor.h" #include "desktop-shell-server-protocol.h" +#include "workspaces-server-protocol.h" #include "../shared/config-parser.h" #define DEFAULT_NUM_WORKSPACES 1 @@ -108,6 +109,8 @@ struct desktop_shell { unsigned int current; unsigned int num; + struct wl_list client_list; + struct weston_animation animation; struct wl_list anim_sticky_list; int anim_dir; @@ -607,6 +610,17 @@ workspace_translate_in(struct workspace *ws, double fraction) } } +static void +broadcast_current_workspace_state(struct desktop_shell *shell) +{ + struct wl_resource *resource; + + wl_list_for_each(resource, &shell->workspaces.client_list, link) + workspace_manager_send_state(resource, + shell->workspaces.current, + shell->workspaces.num); +} + static void reverse_workspace_change_animation(struct desktop_shell *shell, unsigned int index, @@ -771,6 +785,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index) shell->workspaces.anim_to == from) { restore_focus_state(shell, to); reverse_workspace_change_animation(shell, index, from, to); + broadcast_current_workspace_state(shell); return; } @@ -785,6 +800,8 @@ change_workspace(struct desktop_shell *shell, unsigned int index) update_workspace(shell, index, from, to); else animate_workspace_change(shell, index, from, to); + + broadcast_current_workspace_state(shell); } static bool @@ -804,13 +821,41 @@ workspace_has_only(struct workspace *ws, struct weston_surface *surface) return container_of(e, struct weston_surface, layer_link) == surface; } +static void +move_surface_to_workspace(struct desktop_shell *shell, + struct weston_surface *surface, + uint32_t workspace) +{ + struct workspace *from; + struct workspace *to; + struct weston_seat *seat; + + if (workspace == shell->workspaces.current) + return; + + from = get_current_workspace(shell); + to = get_workspace(shell, workspace); + + wl_list_remove(&surface->layer_link); + wl_list_insert(&to->layer.surface_list, &surface->layer_link); + + drop_focus_state(shell, from, surface); + wl_list_for_each(seat, &shell->compositor->seat_list, link) + if (seat->has_keyboard && + seat->keyboard.focus == &surface->surface) + wl_keyboard_set_focus(&seat->keyboard, NULL); + + weston_surface_damage_below(surface); +} + static void take_surface_to_workspace_by_seat(struct desktop_shell *shell, - struct wl_seat *seat, + struct wl_seat *wl_seat, unsigned int index) { + struct weston_seat *seat = (struct weston_seat *) wl_seat; struct weston_surface *surface = - (struct weston_surface *) seat->keyboard->focus; + (struct weston_surface *) wl_seat->keyboard->focus; struct shell_surface *shsurf; struct workspace *from; struct workspace *to; @@ -825,12 +870,17 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell, 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); + replace_focus_state(shell, to, seat); drop_focus_state(shell, from, surface); if (shell->workspaces.anim_from == to && shell->workspaces.anim_to == from) { + wl_list_remove(&to->layer.link); + wl_list_insert(from->layer.link.prev, &to->layer.link); + reverse_workspace_change_animation(shell, index, from, to); + broadcast_current_workspace_state(shell); + return; } @@ -850,6 +900,56 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell, animate_workspace_change(shell, index, from, to); } + + broadcast_current_workspace_state(shell); +} + +static void +workspace_manager_move_surface(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *surface_resource, + uint32_t workspace) +{ + struct desktop_shell *shell = resource->data; + struct weston_surface *surface = + (struct weston_surface *) surface_resource; + + move_surface_to_workspace(shell, surface, workspace); +} + +static const struct workspace_manager_interface workspace_manager_implementation = { + workspace_manager_move_surface, +}; + +static void +unbind_resource(struct wl_resource *resource) +{ + wl_list_remove(&resource->link); + free(resource); +} + +static void +bind_workspace_manager(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct desktop_shell *shell = data; + struct wl_resource *resource; + + resource = wl_client_add_object(client, &workspace_manager_interface, + &workspace_manager_implementation, + id, shell); + + if (resource == NULL) { + weston_log("couldn't add workspace manager object"); + return; + } + + resource->destroy = unbind_resource; + wl_list_insert(&shell->workspaces.client_list, &resource->link); + + workspace_manager_send_state(resource, + shell->workspaces.current, + shell->workspaces.num); } static void @@ -3618,6 +3718,7 @@ shell_init(struct weston_compositor *ec) weston_layer_init(&shell->input_panel_layer, NULL); wl_array_init(&shell->workspaces.array); + wl_list_init(&shell->workspaces.client_list); shell_configuration(shell); @@ -3653,6 +3754,10 @@ shell_init(struct weston_compositor *ec) shell, bind_input_panel) == NULL) return -1; + if (wl_display_add_global(ec->wl_display, &workspace_manager_interface, + shell, bind_workspace_manager) == NULL) + return -1; + shell->child.deathstamp = weston_compositor_get_time(); if (launch_desktop_shell_process(shell) != 0) return -1;