[PATCH 17/19] tablet-shell: add task manager to tablet-shell.

ning.tang at intel.com ning.tang at intel.com
Mon Sep 24 19:40:02 PDT 2012


From: Ning Tang <ning.tang at intel.com>

 Tablet-shell can run multitask. Key binding super + tab will switch
 between applications. Home screen is treated as a special client.
 One client may have several shell surface.
 They would be moved to a list when the client is
 hung. When switched back, shell surfaces will be
 placed in order. Surfaces are inserted in application_layer.
 
 Signed-off-by: Ning Tang <ning.tang at intel.com>
---
 src/tablet-shell.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 194 insertions(+), 29 deletions(-)

diff --git a/src/tablet-shell.c b/src/tablet-shell.c
index 27d0486..7ab37a6 100644
--- a/src/tablet-shell.c
+++ b/src/tablet-shell.c
@@ -29,6 +29,7 @@
 
 #include "compositor.h"
 #include "tablet-shell-server-protocol.h"
+#include <wayland-server.h>
 
 /*
  * TODO: Don't fade back from black until we've received a lockscreen
@@ -42,6 +43,19 @@ enum {
 	STATE_TASK
 };
 
+struct shell_surface;
+
+struct client_task {
+	struct wl_client *client;
+	struct wl_list shsurf_list;
+	struct wl_list link;
+};
+
+struct task_manager {
+	struct wl_list task_list;
+	struct client_task *home_task;
+};
+
 struct tablet_shell {
 	struct wl_resource resource;
 	struct wl_resource client_resource;
@@ -64,6 +78,7 @@ struct tablet_shell {
 	struct wl_listener switcher_listener;
 
 	struct tablet_client *current_client;
+	struct task_manager task_manager;
 
 	int state, previous_state;
 	int long_press_active;
@@ -89,6 +104,7 @@ struct shell_surface {
 		uint32_t framerate;
 	} fullscreen;
 
+	struct client_task *client_task;
 	const struct weston_shell_client *client;
 };
 
@@ -108,6 +124,10 @@ static void
 black_surface_configure(struct weston_surface *es,
 			int32_t sx, int32_t sy);
 
+static void
+tablet_shell_surface_configure(struct weston_surface *es,
+			       int32_t sx, int32_t sy);
+
 static struct shell_surface *
 get_shell_surface(struct weston_surface *surface)
 {
@@ -115,6 +135,8 @@ get_shell_surface(struct weston_surface *surface)
 		return surface->private;
 	else if (surface->configure == black_surface_configure)
 		return get_shell_surface(surface->private);
+	else if (surface->configure == tablet_shell_surface_configure)
+		return surface->private;
 	else
 		return NULL;
 }
@@ -122,16 +144,25 @@ get_shell_surface(struct weston_surface *surface)
 static void
 destroy_shell_surface(struct shell_surface *shsurf)
 {
+	struct tablet_shell *shell = shsurf->shell;
+	struct weston_surface *surface;
 	wl_list_remove(&shsurf->surface_destroy_listener.link);
 	shsurf->surface->configure = NULL;
 
-	if (shsurf->black_surface)
-	{
+	if (shsurf->black_surface) {
 		wl_list_remove(&shsurf->black_surface->layer_link);
 		weston_surface_destroy(shsurf->black_surface);
 	}
-	wl_list_remove(&shsurf->link);
 	free(shsurf);
+	if (shell->state == STATE_HOME ||
+		wl_list_length(&shell->application_layer.surface_list) == 1) {
+		weston_surface_damage(shell->home_surface);
+	} else {
+		surface =
+			container_of(shell->application_layer.surface_list.next,
+				     struct weston_surface, layer_link);
+		weston_surface_damage(surface);
+	}
 }
 
 static void
@@ -290,7 +321,7 @@ create_shell_surface(void *shell, struct weston_surface *surface,
 	}
 
 	shsurf = calloc(1, sizeof *shsurf);
-		if (!shsurf) {
+	if (!shsurf) {
 		weston_log("no memory to allocate shell surface\n");
 		return NULL;
 	}
@@ -330,6 +361,42 @@ static const struct weston_shell_client shell_client = {
 };
 
 static void
+hang_client(struct tablet_shell *shell, int home);
+
+static void
+bring_client_back(struct tablet_shell *shell, struct wl_seat *seat);
+
+static void
+shell_surface_create_client(struct shell_surface *shsurf,
+			    struct wl_client *client)
+{
+	struct client_task *task;
+	task = calloc(1, sizeof *task);
+	task->client = client;
+	wl_list_init(&task->link);
+	wl_list_init(&task->shsurf_list);
+	shsurf->client_task = task;
+}
+
+static void
+shell_surface_add_client(struct shell_surface *shsurf,
+			 struct wl_client *client,
+			 struct tablet_shell *shell)
+{
+	struct weston_surface *surface;
+	struct shell_surface *current_shsurf;
+	surface = container_of(shell->application_layer.surface_list.next,
+			       struct weston_surface, layer_link);
+	current_shsurf = get_shell_surface(surface);
+	if (client == current_shsurf->client_task->client)
+		shsurf->client_task = current_shsurf->client_task;
+	else {
+		hang_client(shell, 0);
+		shell_surface_create_client(shsurf, client);
+	}
+}
+
+static void
 shell_get_shell_surface(struct wl_client *client,
 			struct wl_resource *resource,
 			uint32_t id,
@@ -362,6 +429,13 @@ shell_get_shell_surface(struct wl_client *client,
 	shsurf->resource.data = shsurf;
 
 	wl_client_add_resource(client, &shsurf->resource);
+	if (wl_list_length(&shell->application_layer.surface_list) >= 1)
+		shell_surface_add_client(shsurf, client, shell);
+	else {
+		shell_surface_create_client(shsurf, client);
+		wl_list_insert(shell->task_manager.task_list.prev,
+			       &shell->task_manager.home_task->link);
+	}
 }
 
 static const struct wl_shell_interface shell_implementation = {
@@ -544,6 +618,10 @@ shell_surface_configure(struct weston_surface *surface,
 	struct shell_surface *shsurf = get_shell_surface(surface);
 	struct weston_seat *seat;
 
+	if (shsurf->client_task->link.next &&
+	    shsurf->client_task->link.next != &shsurf->client_task->link)
+		return;
+
 	if (!weston_surface_is_mapped(surface)) {
 		tablet_shell_set_state(shell, STATE_TASK);
 
@@ -617,11 +695,17 @@ tablet_shell_set_homescreen(struct wl_client *client,
 			    struct wl_resource *surface_resource)
 {
 	struct tablet_shell *shell = resource->data;
+	struct shell_surface *shsurf;
 
 	shell->home_surface = surface_resource->data;
 	shell->home_surface->configure = tablet_shell_surface_configure;
 
 	weston_surface_set_position(shell->home_surface, 0, 0);
+	shsurf = calloc(1, sizeof *shsurf);
+	wl_list_init(&shsurf->link);
+	shsurf->surface = shell->home_surface;
+	shell->task_manager.home_task->shsurf_list = shsurf->link;
+	shell->home_surface->private = shsurf;
 }
 
 static void
@@ -775,6 +859,21 @@ launch_ux_daemon(struct tablet_shell *shell)
 }
 
 static void
+task_manager_init(struct tablet_shell *shell)
+{
+	struct client_task *home_task;
+	home_task = calloc(1, sizeof *home_task);
+	if (!home_task) {
+		weston_log("no memory to allocate client task\n");
+		return;
+	}
+	shell->task_manager.home_task = home_task;
+	wl_list_init(&home_task->link);
+	wl_list_init(&home_task->shsurf_list);
+	wl_list_init(&shell->task_manager.task_list);
+}
+
+static void
 toggle_switcher(struct tablet_shell *shell)
 {
 	switch (shell->state) {
@@ -783,7 +882,7 @@ toggle_switcher(struct tablet_shell *shell)
 		break;
 	default:
 		tablet_shell_send_show_switcher(&shell->resource);
-		tablet_shell_set_state(shell, STATE_SWITCHER);
+// 		tablet_shell_set_state(shell, STATE_SWITCHER);
 		break;
 	}
 }
@@ -804,6 +903,7 @@ go_home(struct tablet_shell *shell, struct weston_seat *seat)
 		tablet_shell_send_hide_switcher(&shell->resource);
 
 	weston_surface_activate(shell->home_surface, seat);
+	weston_surface_damage(shell->home_surface);
 
 	tablet_shell_set_state(shell, STATE_HOME);
 }
@@ -822,9 +922,9 @@ long_press_handler(void *data)
 static void
 menu_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
 {
-	struct tablet_shell *shell = data;
+// 	struct tablet_shell *shell = data;
 
-	toggle_switcher(shell);
+// 	toggle_switcher(shell);
 }
 
 static void
@@ -843,7 +943,7 @@ home_key_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
 		switch (shell->state) {
 		case STATE_HOME:
 		case STATE_SWITCHER:
-			toggle_switcher(shell);
+// 			toggle_switcher(shell);
 			break;
 		default:
 			go_home(shell, (struct weston_seat *) seat);
@@ -881,40 +981,101 @@ force_kill_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
 {
 	struct tablet_shell *shell = data;
 	struct wl_client *client;
-	struct weston_surface * focus;
-	struct shell_surface * shsurf;
+	struct weston_surface *focus;
+	struct shell_surface *shsurf = NULL;
 	pid_t pid;
 	uid_t uid;
 	gid_t gid;
-	int client_cnt;
 
 	if (!seat->keyboard->focus)
 		return;
-	client = seat->keyboard->focus->resource.client;
-	shsurf = get_shell_surface(seat->keyboard->focus);
+	focus = container_of(shell->application_layer.surface_list.next,
+			     struct weston_surface, layer_link);
+	if (focus)
+		shsurf = get_shell_surface(focus);
 	if (!shsurf)
 		return;
 
+	if (shell->state != STATE_TASK)
+		return;
+	client = focus->surface.resource.client;
 	wl_client_get_credentials(client, &pid, &uid, &gid);
-	client_cnt = wl_list_length(&shell->application_layer.surface_list);
-	if (client_cnt > 2) {
-		wl_list_for_each(focus, &shell->application_layer.surface_list,
-				 layer_link) {
-			client_cnt--;
-			if (client_cnt < 2) {
-				weston_surface_activate(focus, seat);
-				break;
-			}
+	kill(pid, SIGKILL);
+	bring_client_back(shell, seat);
+	weston_compositor_schedule_repaint(shell->compositor);
+}
+
+static void
+bring_client_back(struct tablet_shell *shell, struct wl_seat *seat)
+{
+	struct shell_surface *shsurf;
+	struct client_task *task;
+	task = container_of(shell->task_manager.task_list.next,
+			    struct client_task, link);
+	wl_list_remove(&task->link);
+	wl_list_init(&task->link);
+	if (task == shell->task_manager.home_task) {
+		go_home(shell, seat);
+		return;
+	}
+	tablet_shell_set_state(shell, STATE_TASK);
+	while (wl_list_length(&task->shsurf_list)) {
+		shsurf = container_of(task->shsurf_list.prev,
+				      struct shell_surface, link);
+		wl_list_remove(&shsurf->link);
+		wl_list_insert(&shell->application_layer.surface_list,
+			       &shsurf->surface->layer_link);
+		weston_surface_damage(shsurf->surface);
+		if (shsurf->black_surface) {
+			wl_list_insert(&shsurf->surface->layer_link,
+				       &shsurf->black_surface->layer_link);
+			weston_surface_damage(shsurf->black_surface);
 		}
+		weston_surface_activate(shsurf->surface, seat);
 	}
-	else
-		focus = NULL;
-	kill(pid, SIGKILL);
-	if (focus == NULL) {
-		tablet_shell_set_state(shell, STATE_HOME);
-		weston_surface_activate(shell->home_surface, seat);
+}
+
+static void
+hang_client(struct tablet_shell *shell, int home)
+{
+	struct weston_surface *surface;
+	struct shell_surface *shsurf;
+	struct client_task *task;
+	if (home) {
+		task = shell->task_manager.home_task;
+		wl_list_insert(shell->task_manager.task_list.prev,
+			       &task->link);
+		return;
 	}
-	weston_compositor_schedule_repaint(shell->compositor);
+	while (wl_list_length(&shell->application_layer.surface_list)) {
+		surface =
+			container_of(shell->application_layer.surface_list.next,
+				     struct weston_surface, layer_link);
+		shsurf = get_shell_surface(surface);
+		task = shsurf->client_task;
+		wl_list_insert(task->shsurf_list.prev, &shsurf->link);
+		wl_list_remove(&shsurf->surface->layer_link);
+		wl_list_init(&shsurf->surface->layer_link);
+		if (shsurf->black_surface) {
+			wl_list_remove(&shsurf->black_surface->layer_link);
+			wl_list_init(&shsurf->black_surface->layer_link);
+		}
+	}
+	wl_list_insert(shell->task_manager.task_list.prev,
+		       &task->link);
+}
+
+static void
+switch_task(struct wl_seat *seat, uint32_t time, uint32_t key,
+		   void *data)
+{
+	struct tablet_shell *shell = data;
+
+	if (wl_list_length(&shell->application_layer.surface_list) != 0)
+		hang_client(shell, 0);
+	else if (shell->state == STATE_HOME)
+		hang_client(shell, 1);
+	bring_client_back(shell, seat);
 }
 
 static void
@@ -1034,6 +1195,9 @@ module_init(struct weston_compositor *compositor)
 					     shell);
 	weston_compositor_add_key_binding(compositor, KEY_ESC, 0,
 					  force_kill_binding, shell);
+	weston_compositor_add_key_binding(compositor, KEY_TAB,
+					  MODIFIER_SUPER,
+					  switch_task, shell);
 	weston_compositor_add_key_binding(compositor, KEY_T,
 					  MODIFIER_CTRL, launch_terminal,
 					  shell);
@@ -1042,6 +1206,7 @@ module_init(struct weston_compositor *compositor)
 			  &compositor->cursor_layer.link);
 	weston_layer_init(&shell->application_layer,
 			  &compositor->cursor_layer.link);
+	task_manager_init(shell);
 	launch_ux_daemon(shell);
 
 	tablet_shell_set_state(shell, STATE_STARTING);
-- 
1.7.12.1



More information about the wayland-devel mailing list