shell: Introduce workspace manager interface
authorJonas Ådahl <jadahl@gmail.com>
Wed, 29 Aug 2012 20:13:01 +0000 (22:13 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Fri, 31 Aug 2012 23:51:49 +0000 (19:51 -0400)
The workspace manager interface purpose is to provide clients with
control and knowledge about the current workspace state. Initially only
one function and one event exists; moving a surface and state updated
event. A workspace is represented as an index in a 1 dimensional array.

A client keeps track of the state by being broadcasted events when the
state changes, currently limited to current workspace or number of
workspaces available.

A client can send an asynchronous request to the manager asking to move
a surface to workspace identified by an index. It is up to the shell to
actually move it.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
protocol/Makefile.am
protocol/workspaces.xml [new file with mode: 0644]
src/Makefile.am
src/shell.c

index 22cb2c9..bf5ef99 100644 (file)
@@ -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 (file)
index 0000000..22f4802
--- /dev/null
@@ -0,0 +1,27 @@
+<protocol name="workspaces">
+
+  <interface name="workspace_manager" version="1">
+    <description summary="workspaces manager">
+      An interface for managing surfaces in workspaces.
+    </description>
+
+    <request name="move_surface">
+      <description summary="move surface to workspace">
+       Move the given surface to the specified workspace.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="workspace" type="uint"/>
+    </request>
+
+    <event name="state">
+      <description summary="workspace state">
+       The current workspace state, such as current workspace and workspace
+       count, has changed.
+      </description>
+      <arg name="current" type="uint"/>
+      <arg name="count" type="uint"/>
+    </event>
+
+  </interface>
+
+</protocol>
index 8096849..028735e 100644 (file)
@@ -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)
index 1213014..20bc355 100644 (file)
@@ -35,6 +35,7 @@
 #include <wayland-server.h>
 #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;
@@ -608,6 +611,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,
                                   struct workspace *from,
@@ -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
@@ -805,12 +822,40 @@ workspace_has_only(struct workspace *ws, struct weston_surface *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;