[PATCH 2/2 v2] shell: account for the subsurfaces when going fullscreen or maximizing

Giulio Camuffo giuliocamuffo at gmail.com
Tue Feb 26 05:35:32 PST 2013


We must calculate the bounding box of the surface + subsurfaces set and use
that when maximizing the window or going fullscreen.
---
 src/shell.c | 83 +++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 62 insertions(+), 21 deletions(-)

diff --git a/src/shell.c b/src/shell.c
index 6960fcd..1eb4253 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1183,11 +1183,35 @@ static const struct wl_pointer_grab_interface resize_grab_interface = {
 	resize_grab_button,
 };
 
+/*
+ * Returns the bounding box of a surface and all its sub-surfaces,
+ * in the surface coordinates system. */
+static pixman_box32_t *
+surface_subsurfaces_boundingbox(struct weston_surface *surface) {
+	pixman_region32_t region;
+	struct weston_subsurface *subsurface;
+
+	pixman_region32_init_rect(&region, 0, 0,
+	                          surface->geometry.width,
+	                          surface->geometry.height);
+
+	wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
+		pixman_region32_union_rect(&region, &region,
+		                           subsurface->position.x,
+		                           subsurface->position.y,
+		                           subsurface->surface->geometry.width,
+		                           subsurface->surface->geometry.height);
+	}
+
+	return pixman_region32_extents(&region);
+}
+
 static int
 surface_resize(struct shell_surface *shsurf,
 	       struct weston_seat *ws, uint32_t edges)
 {
 	struct weston_resize_grab *resize;
+	pixman_box32_t *boundingbox;
 
 	if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
 		return 0;
@@ -1200,9 +1224,11 @@ surface_resize(struct shell_surface *shsurf,
 	if (!resize)
 		return -1;
 
+	boundingbox = surface_subsurfaces_boundingbox(shsurf->surface);
+
 	resize->edges = edges;
-	resize->width = shsurf->surface->geometry.width;
-	resize->height = shsurf->surface->geometry.height;
+	resize->width = boundingbox->x2 - boundingbox->x1;
+	resize->height = boundingbox->y2 - boundingbox->y1;
 
 	shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
 			 ws->seat.pointer, edges);
@@ -1688,6 +1714,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 	struct weston_surface *surface = shsurf->surface;
 	struct weston_matrix *matrix;
 	float scale, output_aspect, surface_aspect, x, y;
+	pixman_box32_t *boundingbox;
+	int32_t width, height;
 
 	if (!shsurf->fullscreen.black_surface)
 		shsurf->fullscreen.black_surface =
@@ -1702,6 +1730,10 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 		       &shsurf->fullscreen.black_surface->layer_link);
 	shsurf->fullscreen.black_surface->output = output;
 
+	boundingbox = surface_subsurfaces_boundingbox(surface);
+	width = boundingbox->x2 - boundingbox->x1;
+	height = boundingbox->y2 - boundingbox->y1;
+
 	switch (shsurf->fullscreen.type) {
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
 		if (surface->buffer_ref.buffer)
@@ -1709,9 +1741,10 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
 		/* 1:1 mapping between surface and output dimensions */
-		if (output->width == surface->geometry.width &&
-		    output->height == surface->geometry.height) {
-			weston_surface_set_position(surface, output->x, output->y);
+		if (output->width == width &&
+		    output->height == height) {
+			weston_surface_set_position(surface, output->x - boundingbox->x1,
+			                                     output->y - boundingbox->y1);
 			break;
 		}
 
@@ -1724,33 +1757,33 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 			(float) surface->geometry.height;
 		if (output_aspect < surface_aspect)
 			scale = (float) output->width /
-				(float) surface->geometry.width;
+				(float) width;
 		else
 			scale = (float) output->height /
-				(float) surface->geometry.height;
+				(float) height;
 
 		weston_matrix_scale(matrix, scale, scale, 1);
 		wl_list_remove(&shsurf->fullscreen.transform.ptr.link);
 		wl_list_insert(&surface->geometry.transformation_list,
 			       &shsurf->fullscreen.transform.ptr.link);
-		x = output->x + (output->width - surface->geometry.width * scale) / 2;
-		y = output->y + (output->height - surface->geometry.height * scale) / 2;
+		x = output->x + (output->width - width * scale) / 2 - boundingbox->x1;
+		y = output->y + (output->height - height * scale) / 2 - boundingbox->y1;
 		weston_surface_set_position(surface, x, y);
 
 		break;
 	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
 		if (shell_surface_is_top_fullscreen(shsurf)) {
 			struct weston_mode mode = {0,
-				surface->geometry.width,
-				surface->geometry.height,
+				width,
+				height,
 				shsurf->fullscreen.framerate};
 
 			if (weston_output_switch_mode(output, &mode) == 0) {
 				weston_surface_configure(shsurf->fullscreen.black_surface,
-					                 output->x, output->y,
+					                 output->x - boundingbox->x1,
+					                 output->y - boundingbox->y1,
 							 output->width,
 							 output->height);
-				weston_surface_set_position(surface, output->x, output->y);
 				break;
 			}
 		}
@@ -3001,12 +3034,16 @@ hide_input_panels(struct wl_listener *listener, void *data)
 static void
 center_on_output(struct weston_surface *surface, struct weston_output *output)
 {
-	int32_t width = weston_surface_buffer_width(surface);
-	int32_t height = weston_surface_buffer_height(surface);
+	pixman_box32_t *boundingbox;
+	int32_t width, height;
 	float x, y;
 
-	x = output->x + (output->width - width) / 2;
-	y = output->y + (output->height - height) / 2;
+	boundingbox = surface_subsurfaces_boundingbox(surface);
+	width = boundingbox->x2 - boundingbox->x1;
+	height = boundingbox->y2 - boundingbox->y1;
+
+	x = output->x + (output->width - width) / 2 - boundingbox->x1 / 2;
+	y = output->y + (output->height - height) / 2 - boundingbox->y1 / 2;
 
 	weston_surface_configure(surface, x, y, width, height);
 }
@@ -3084,6 +3121,7 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
 	struct weston_seat *seat;
 	struct workspace *ws;
 	int panel_height = 0;
+	pixman_box32_t *boundingbox;
 
 	surface->geometry.width = width;
 	surface->geometry.height = height;
@@ -3101,8 +3139,9 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
 	case SHELL_SURFACE_MAXIMIZED:
 		/* use surface configure to set the geometry */
 		panel_height = get_output_panel_height(shell,surface->output);
-		weston_surface_set_position(surface, shsurf->output->x,
-					    shsurf->output->y + panel_height);
+		boundingbox = surface_subsurfaces_boundingbox(shsurf->surface);
+		weston_surface_set_position(surface, shsurf->output->x - boundingbox->x1,
+					    shsurf->output->y + panel_height - boundingbox->y1);
 		break;
 	case SHELL_SURFACE_POPUP:
 		shell_map_popup(shsurf);
@@ -3176,6 +3215,7 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
 {
 	enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
 	struct shell_surface *shsurf;
+	pixman_box32_t *boundingbox;
 
 	shsurf = get_shell_surface(surface);
 	if (shsurf)
@@ -3190,9 +3230,10 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
 		break;
 	case SHELL_SURFACE_MAXIMIZED:
 		/* setting x, y and using configure to change that geometry */
-		surface->geometry.x = surface->output->x;
+		boundingbox = surface_subsurfaces_boundingbox(shsurf->surface);
+		surface->geometry.x = surface->output->x - boundingbox->x1;
 		surface->geometry.y = surface->output->y +
-			get_output_panel_height(shell,surface->output);
+			get_output_panel_height(shell,surface->output) - boundingbox->y1;
 		break;
 	case SHELL_SURFACE_TOPLEVEL:
 		break;
-- 
1.8.1.3



More information about the wayland-devel mailing list