[PATCH 2/2] Notify clients on mode_switch()

Hardening rdp.effort at gmail.com
Wed Sep 18 14:56:36 PDT 2013


This patch implements the notification of clients during mode_switch.
As discussed on IRC, clients are notified of mode_switch only when the
"native" mode is changed and activated. That means that if the native
mode is changed and the compositor had activated a temporary mode for
a fullscreen surface, the clients will be notified only when the native
mode is restored.
The scaling factor is treated the same way as modes.
---
 src/compositor-drm.c      |  1 -
 src/compositor-fbdev.c    |  1 -
 src/compositor-headless.c |  1 -
 src/compositor-rdp.c      | 29 ++++++++-------
 src/compositor-rpi.c      |  1 -
 src/compositor-wayland.c  |  1 -
 src/compositor-x11.c      |  1 -
 src/compositor.c          | 91 ++++++++++++++++++++++++++++++++++++++++++-----
 src/compositor.h          | 13 +++++--
 src/shell.c               | 12 ++++---
 10 files changed, 117 insertions(+), 34 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 2451e6a..982e84e 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1943,7 +1943,6 @@ create_output_for_connector(struct drm_compositor *ec,
 	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
 		output->base.connection_internal = 1;
 
-	output->base.original_mode = output->base.current_mode;
 	output->base.start_repaint_loop = drm_output_start_repaint_loop;
 	output->base.repaint = drm_output_repaint;
 	output->base.destroy = drm_output_destroy;
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 520340b..f76c264 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -544,7 +544,6 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
 
 	output->base.current_mode = &output->mode;
-	output->base.original_mode = &output->mode;
 	output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
 	output->base.make = "unknown";
 	output->base.model = output->fb_info.id;
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 3761be1..2a0b0c3 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -120,7 +120,6 @@ headless_compositor_create_output(struct headless_compositor *c,
 	output->finish_frame_timer =
 		wl_event_loop_add_timer(loop, finish_frame_handler, output);
 
-	output->base.original_mode = output->base.current_mode;
 	output->base.start_repaint_loop = headless_output_start_repaint_loop;
 	output->base.repaint = headless_output_repaint;
 	output->base.destroy = headless_output_destroy;
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index 642a6b7..69f1d04 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -372,9 +372,10 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
 	if(local_mode == output->current_mode)
 		return 0;
 
-	output->current_mode->flags = 0;
+	output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
+
 	output->current_mode = local_mode;
-	output->current_mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+	output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
 
 	pixman_renderer_output_destroy(output);
 	pixman_renderer_output_create(output);
@@ -466,7 +467,7 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
 		goto out_free_output_and_modes;
 	}
 
-	output->base.current_mode = currentMode;
+	output->base.current_mode = output->base.native_mode = currentMode;
 	weston_output_init(&output->base, &c->base, 0, 0, width, height,
 			   WL_OUTPUT_TRANSFORM_NORMAL, 1);
 
@@ -489,7 +490,6 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
 	loop = wl_display_get_event_loop(c->base.wl_display);
 	output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
 
-	output->base.original_mode = output->base.current_mode;
 	output->base.start_repaint_loop = rdp_output_start_repaint_loop;
 	output->base.repaint = rdp_output_repaint;
 	output->base.destroy = rdp_output_destroy;
@@ -679,23 +679,26 @@ xf_peer_post_connect(freerdp_peer* client)
 	output = c->output;
 	settings = client->settings;
 
-	if(!settings->SurfaceCommandsEnabled) {
+	if (!settings->SurfaceCommandsEnabled) {
 		weston_log("client doesn't support required SurfaceCommands\n");
 		return FALSE;
 	}
 
-	if(output->base.width != (int)settings->DesktopWidth ||
+	if (output->base.width != (int)settings->DesktopWidth ||
 			output->base.height != (int)settings->DesktopHeight)
 	{
-		if(!settings->DesktopResize) {
-			weston_log("client don't support desktopResize()\n");
+		struct weston_mode new_mode;
+		struct weston_mode *target_mode;
+		new_mode.width = (int)settings->DesktopWidth;
+		new_mode.height = (int)settings->DesktopHeight;
+		target_mode = find_matching_mode(&output->base, &new_mode);
+		if (!target_mode) {
+			weston_log("client mode not found\n");
 			return FALSE;
 		}
-
-		/* force the client size */
-		settings->DesktopWidth = output->base.width;
-		settings->DesktopHeight = output->base.height;
-		client->update->DesktopResize(client->context);
+		weston_output_switch_mode(&output->base, target_mode, 1, WESTON_MODE_SWITCH_SET_NATIVE);
+		output->base.width = new_mode.width;
+		output->base.height = new_mode.height;
 	}
 
 	weston_log("kbd_layout:%x kbd_type:%x kbd_subType:%x kbd_functionKeys:%x\n",
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index a5322e0..3b8a3c5 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -369,7 +369,6 @@ rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
 
 	output->base.current_mode = &output->mode;
-	output->base.original_mode = &output->mode;
 	output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
 	output->base.make = "unknown";
 	output->base.model = "unknown";
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4caad81..2b8b956 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -295,7 +295,6 @@ wayland_compositor_create_output(struct wayland_compositor *c,
 				      &shell_surface_listener, output);
 	wl_shell_surface_set_toplevel(output->parent.shell_surface);
 
-	output->base.original_mode = output->base.current_mode;
 	output->base.start_repaint_loop = wayland_output_start_repaint_loop;
 	output->base.repaint = wayland_output_repaint;
 	output->base.destroy = wayland_output_destroy;
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 1dd5037..704e751 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -892,7 +892,6 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
 	output->base.set_dpms = NULL;
 	output->base.switch_mode = NULL;
 	output->base.current_mode = &output->mode;
-	output->base.original_mode = output->base.current_mode;
 	output->base.make = "xwayland";
 	output->base.model = "none";
 	weston_output_init(&output->base, &c->base,
diff --git a/src/compositor.c b/src/compositor.c
index eeb0ab5..bf04ddd 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -96,20 +96,76 @@ static void
 weston_compositor_build_surface_list(struct weston_compositor *compositor);
 
 WL_EXPORT int
-weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale)
+weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,
+		int32_t scale, enum weston_mode_switch_op op)
 {
 	struct weston_seat *seat;
+	struct wl_resource *resource;
 	pixman_region32_t old_output_region;
-	int ret;
+	int ret, notify_mode_changed, notify_scale_changed;
+	int temporary_mode, temporary_scale;
 
 	if (!output->switch_mode)
 		return -1;
 
-	ret = output->switch_mode(output, mode);
-	if (ret < 0)
-		return ret;
+	temporary_mode = (output->original_mode != 0);
+	temporary_scale = (output->current_scale != output->original_scale);
+	ret = 0;
+
+	notify_mode_changed = 0;
+	notify_scale_changed = 0;
+	switch(op) {
+	case WESTON_MODE_SWITCH_SET_NATIVE:
+		output->native_mode = mode;
+		if (!temporary_mode) {
+			notify_mode_changed = 1;
+			ret = output->switch_mode(output, mode);
+			if (ret < 0)
+				return ret;
+		}
+
+		output->native_scale = scale;
+		if(!temporary_scale)
+			notify_scale_changed = 1;
+		break;
+	case WESTON_MODE_SWITCH_SET_TEMPORARY:
+		if (!temporary_mode)
+			output->original_mode = output->native_mode;
+		if (!temporary_scale)
+			output->original_scale = output->native_scale;
+
+		ret = output->switch_mode(output, mode);
+		if (ret < 0)
+			return ret;
 
-        output->current_scale = scale;
+		output->current_mode = mode;
+		output->current_scale = scale;
+		break;
+	case WESTON_MODE_SWITCH_RESTORE_NATIVE:
+		if (!temporary_mode) {
+			weston_log("already in the native mode\n");
+			return -1;
+		}
+
+		notify_mode_changed = (output->original_mode != output->native_mode);
+
+		ret = output->switch_mode(output, mode);
+		if (ret < 0)
+			return ret;
+
+		if (output->original_scale != output->native_scale) {
+			notify_scale_changed = 1;
+			scale = output->native_scale;
+			output->original_scale = scale;
+		}
+		output->original_mode = 0;
+
+		output->current_scale = output->native_scale;
+		break;
+	default:
+		weston_log("unknown weston_switch_mode_op %d\n", op);
+		break;
+	}
 
 	pixman_region32_init(&old_output_region);
 	pixman_region32_copy(&old_output_region, &output->region);
@@ -152,6 +208,25 @@ weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode
 
 	pixman_region32_fini(&old_output_region);
 
+	/* notify clients of the changes */
+	if (notify_mode_changed || notify_scale_changed) {
+		wl_resource_for_each(resource, &output->resource_list) {
+			if(notify_mode_changed) {
+				wl_output_send_mode(resource,
+						mode->flags | WL_OUTPUT_MODE_CURRENT,
+						mode->width,
+						mode->height,
+						mode->refresh);
+			}
+
+			if (notify_scale_changed)
+				wl_output_send_scale(resource, scale);
+
+			if (wl_resource_get_version(resource) >= 2)
+				   wl_output_send_done(resource);
+		}
+	}
+
 	return ret;
 }
 
@@ -1874,7 +1949,7 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
 	 * If this commit would cause the surface to move by the
 	 * attach(dx, dy) parameters, the old damage region must be
 	 * translated to correspond to the new surface coordinate system
-	 * origin.
+	 * original_mode.
 	 */
 	pixman_region32_translate(&sub->cached.damage,
 				  -surface->pending.sx, -surface->pending.sy);
@@ -2728,7 +2803,7 @@ weston_output_transform_scale_init(struct weston_output *output, uint32_t transf
 		break;
 	}
 
-        output->current_scale = scale;
+	output->native_scale = output->current_scale = scale;
 	output->width /= scale;
 	output->height /= scale;
 }
diff --git a/src/compositor.h b/src/compositor.h
index 02f581f..b798de7 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -174,6 +174,12 @@ enum dpms_enum {
 	WESTON_DPMS_OFF
 };
 
+enum weston_mode_switch_op {
+	WESTON_MODE_SWITCH_SET_NATIVE,
+	WESTON_MODE_SWITCH_SET_TEMPORARY,
+	WESTON_MODE_SWITCH_RESTORE_NATIVE
+};
+
 struct weston_output {
 	uint32_t id;
 	char *name;
@@ -203,11 +209,13 @@ struct weston_output {
 	char *make, *model, *serial_number;
 	uint32_t subpixel;
 	uint32_t transform;
+	int32_t native_scale;
 	int32_t current_scale;
+	int32_t original_scale;
 
+	struct weston_mode *native_mode;
 	struct weston_mode *current_mode;
 	struct weston_mode *original_mode;
-	int32_t original_scale;
 	struct wl_list mode_list;
 
 	void (*start_repaint_loop)(struct weston_output *output);
@@ -1211,7 +1219,8 @@ void
 weston_surface_destroy(struct weston_surface *surface);
 
 int
-weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale);
+weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,
+			int32_t scale, enum weston_mode_switch_op op);
 
 int
 noop_renderer_init(struct weston_compositor *ec);
diff --git a/src/shell.c b/src/shell.c
index c1e0109..d1847f5 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1627,11 +1627,12 @@ get_default_output(struct weston_compositor *compositor)
 static void
 restore_output_mode(struct weston_output *output)
 {
-	if (output->current != output->origin ||
-	    (int32_t)output->scale != output->origin_scale)
+	if (output->current_mode != output->original_mode ||
+	    (int32_t)output->current_scale != output->original_scale)
 		weston_output_switch_mode(output,
-					  output->origin,
-					  output->origin_scale);
+					  output->original_mode,
+					  output->original_scale,
+					  WESTON_MODE_SWITCH_RESTORE_NATIVE);
 }
 
 static void
@@ -1958,7 +1959,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
 				surf_height * surface->buffer_scale,
 				shsurf->fullscreen.framerate};
 
-			if (weston_output_switch_mode(output, &mode, surface->buffer_scale) == 0) {
+			if (weston_output_switch_mode(output, &mode, surface->buffer_scale,
+					WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
 				weston_surface_set_position(surface,
 							    output->x - surf_x,
 							    output->y - surf_y);
-- 
1.8.1.2



More information about the wayland-devel mailing list