[PATCH v2 4/4] shell: Implement "driver" method of fullsceen.

zhiwen.wu at linux.intel.com zhiwen.wu at linux.intel.com
Tue Mar 13 08:18:26 PDT 2012


From: Alex Wu <zhiwen.wu at linux.intel.com>

Switching display mode may happen when:
1. The fullscreen surface is at top most in fullscreen layer and with
   "driver" method. Shell will switch output mode to match the surface
   size. If no matched mode found, fall back to "fill" method.
2. The top fullscreen surface is destroyed or unset. Switch back to the
   origin mode.
---
 src/compositor-drm.c     |    1 +
 src/compositor-openwfd.c |    1 +
 src/compositor-wayland.c |    1 +
 src/compositor-x11.c     |    1 +
 src/compositor.h         |    1 +
 src/shell.c              |   80 ++++++++++++++++++++++++++++++++++++++--------
 6 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index e81b5a4..980a5b5 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1334,6 +1334,7 @@ create_output_for_connector(struct drm_compositor *ec,
 
 	wl_list_insert(ec->base.output_list.prev, &output->base.link);
 
+	output->base.origin = output->base.current;
 	output->scanout_buffer_destroy_listener.func =
 		output_handle_scanout_buffer_destroy;
 	output->pending_scanout_buffer_destroy_listener.func =
diff --git a/src/compositor-openwfd.c b/src/compositor-openwfd.c
index bbf1067..3548dfb 100644
--- a/src/compositor-openwfd.c
+++ b/src/compositor-openwfd.c
@@ -401,6 +401,7 @@ create_output_for_port(struct wfd_compositor *ec,
 
 	wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE);
 
+	output->base.origin = output->base.current;
 	output->base.repaint = wfd_output_repaint;
 	output->base.prepare_scanout_surface =
 		wfd_output_prepare_scanout_surface;
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index c7bb5ed..f0e75f9 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -433,6 +433,7 @@ wayland_compositor_create_output(struct wayland_compositor *c,
 	/* FIXME: add shell_surface listener for resizing */
 	wl_shell_surface_set_toplevel(output->parent.shell_surface);
 
+	output->base.origin = output->base.current;
 	output->base.repaint = wayland_output_repaint;
 	output->base.destroy = wayland_output_destroy;
 	output->base.assign_planes = NULL;
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 18540fe..a3f4a62 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -443,6 +443,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 	output->finish_frame_timer =
 		wl_event_loop_add_timer(loop, finish_frame_handler, output);
 
+	output->base.origin = output->base.current;
 	output->base.repaint = x11_output_repaint;
 	output->base.destroy = x11_output_destroy;
 	output->base.assign_planes = NULL;
diff --git a/src/compositor.h b/src/compositor.h
index 07b39d6..434ccd6 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -90,6 +90,7 @@ struct weston_output {
 	uint32_t subpixel;
 	
 	struct weston_mode *current;
+	struct weston_mode *origin;
 	struct wl_list mode_list;
 
 	void (*repaint)(struct weston_output *output,
diff --git a/src/shell.c b/src/shell.c
index 984c75d..2e7b77d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -151,6 +151,26 @@ static void
 center_on_output(struct weston_surface *surface,
 		 struct weston_output *output);
 
+static struct wl_shell *
+shell_surface_get_shell(struct shell_surface *shsurf);
+
+static bool
+shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
+{
+	struct wl_shell *shell;
+	struct weston_surface *top_fs_es;
+
+	shell = shell_surface_get_shell(shsurf);
+	
+	if (wl_list_empty(&shell->fullscreen_layer.surface_list))
+		return false;
+
+	top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
+			         struct weston_surface, 
+				 layer_link);
+	return (shsurf == get_shell_surface(top_fs_es));
+}
+
 static void
 shell_configuration(struct wl_shell *shell)
 {
@@ -375,11 +395,18 @@ static void
 shell_unset_fullscreen(struct shell_surface *shsurf)
 {
 	/* undo all fullscreen things here */
+	if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
+	    shell_surface_is_top_fullscreen(shsurf)) {
+		weston_output_switch_mode(shsurf->fullscreen_output,
+		                          shsurf->fullscreen_output->origin);
+	}
+
 	shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
 	shsurf->fullscreen.framerate = 0;
 	wl_list_remove(&shsurf->fullscreen.transform.link);
 	wl_list_init(&shsurf->fullscreen.transform.link);
-	weston_surface_destroy(shsurf->fullscreen.black_surface);
+	if (shsurf->fullscreen.black_surface)
+		weston_surface_destroy(shsurf->fullscreen.black_surface);
 	shsurf->fullscreen.black_surface = NULL;
 	shsurf->fullscreen_output = NULL;
 	shsurf->surface->force_configure = 1;
@@ -575,7 +602,21 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 		weston_surface_set_position(surface, output->x, output->y);
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
-		break;
+		if (shell_surface_is_top_fullscreen(shsurf)) {
+			struct weston_mode mode = {0, 
+				                   surface->geometry.width,
+						   surface->geometry.height,
+						   shsurf->fullscreen.framerate};
+
+			if (weston_output_switch_mode(output, &mode) == 0) {
+				weston_surface_configure(shsurf->fullscreen.black_surface, 
+						         output->x, output->y,
+							 output->current->width,
+							 output->current->height);
+				weston_surface_set_position(surface, output->x, output->y);
+				break;
+			}
+		}
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
 		break;
 	default:
@@ -587,26 +628,33 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 static void
 shell_stack_fullscreen(struct shell_surface *shsurf)
 {
+	struct weston_output *output = shsurf->fullscreen_output;
 	struct weston_surface *surface = shsurf->surface;
 	struct wl_shell *shell = shell_surface_get_shell(shsurf);
 
 	wl_list_remove(&surface->layer_link);
-	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
-
 	wl_list_insert(&shell->fullscreen_layer.surface_list,
 		       &surface->layer_link);
+	weston_surface_damage(surface);
+
+	if (!shsurf->fullscreen.black_surface)
+		shsurf->fullscreen.black_surface =
+			create_black_surface(surface->compositor,
+					     output->x, output->y,
+					     output->current->width,
+					     output->current->height);
+
+	wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
 	wl_list_insert(&surface->layer_link,
 		       &shsurf->fullscreen.black_surface->layer_link);
-
-	weston_surface_damage(surface);
 	weston_surface_damage(shsurf->fullscreen.black_surface);
 }
 
 static void
 shell_map_fullscreen(struct shell_surface *shsurf)
 {
-	shell_configure_fullscreen(shsurf);
 	shell_stack_fullscreen(shsurf);
+	shell_configure_fullscreen(shsurf);
 }
 
 static void
@@ -773,13 +821,20 @@ destroy_shell_surface(struct wl_resource *resource)
 	if (shsurf->popup.grab.input_device)
 		wl_input_device_end_pointer_grab(shsurf->popup.grab.input_device, 0);
 
-	/* in case cleaning up a dead client destroys shell_surface first */
-	if (shsurf->surface)
-		wl_list_remove(&shsurf->surface_destroy_listener.link);
+	if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
+	    shell_surface_is_top_fullscreen(shsurf)) {
+		weston_output_switch_mode(shsurf->fullscreen_output,
+					  shsurf->fullscreen_output->origin);
+	}
 
 	if (shsurf->fullscreen.black_surface)
 		weston_surface_destroy(shsurf->fullscreen.black_surface);
 
+	/* Since destroy_resource() use wl_list_for_each_safe(),
+	 * we can always remove the listener.
+	 */
+	wl_list_remove(&shsurf->surface_destroy_listener.link);
+
 	wl_list_remove(&shsurf->link);
 	free(shsurf);
 }
@@ -792,7 +847,6 @@ shell_handle_surface_destroy(struct wl_listener *listener,
 						    struct shell_surface,
 						    surface_destroy_listener);
 
-	shsurf->surface = NULL;
 	wl_resource_destroy(&shsurf->resource, time);
 }
 
@@ -1644,7 +1698,6 @@ configure(struct weston_shell *base, struct weston_surface *surface,
 {
 	struct wl_shell *shell = container_of(base, struct wl_shell, shell);
 	enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
-	enum shell_surface_type prev_surface_type = SHELL_SURFACE_NONE;
 	struct shell_surface *shsurf;
 
 	shsurf = get_shell_surface(surface);
@@ -1662,9 +1715,8 @@ configure(struct weston_shell *base, struct weston_surface *surface,
 		center_on_output(surface, shsurf->fullscreen_output);
 		break;
 	case SHELL_SURFACE_FULLSCREEN:
+		shell_stack_fullscreen(shsurf);
 		shell_configure_fullscreen(shsurf);
-		if (prev_surface_type != SHELL_SURFACE_FULLSCREEN)
-			shell_stack_fullscreen(shsurf);
 		break;
 	case SHELL_SURFACE_MAXIMIZED:
 		/* setting x, y and using configure to change that geometry */
-- 
1.7.5.4



More information about the wayland-devel mailing list