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;