Notify clients on mode_switch()

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.
diff --git a/src/compositor.c b/src/compositor.c
index 50ec739..e138e99 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -96,20 +96,76 @@
 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;
 
-        output->current_scale = scale;
+	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_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 @@
 
 	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 @@
 	 * 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 @@
 		break;
 	}
 
-        output->current_scale = scale;
+	output->native_scale = output->current_scale = scale;
 	output->width /= scale;
 	output->height /= scale;
 }