<div dir="ltr">I'll try to recap IRC.<div><br></div><div style>There is an error in the way you implemented weston_switch_mode in the following scenario:  A client sets a fullscreen surface at the same resolution and refresh rate as the "native" mode.  After this, a native mode switch occurs for some reason.  Because origin_mode == native_mode, your implementation will not detect the fullscreen surface and will mode-switch out from under the client.  My recommendation would be to use origin_mode != NULL to indicate that the current mode is temporary.</div>
<div style><br></div><div style>Also, I think it would be better to call it MODE_SWITCH_SET_TEMPORARY rather than MODE_SWITCH_SET_FULLSCREEN.  The former is more descriptive of what is actually happening to the output and the latter is highly wl_shell dependent (there may be temporary switches that are not caused by a fullscreen surface).</div>
<div style><br></div><div style>--Jason Ekstrand</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Sep 10, 2013 at 5:28 PM, Hardening <span dir="ltr"><<a href="mailto:rdp.effort@gmail.com" target="_blank">rdp.effort@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This patch implements the notification of clients during mode_switch.<br>
As discussed on IRC, clients are notified of mode_switch only when the<br>
"native" mode is changed and activated. That means that if the native<br>
mode is changed and the compositor had activated a temporary mode for<br>
a fullscreen surface, the clients will be notified only when the native<br>
mode is restored.<br>
The scaling factor is treated the same way as modes.<br>
---<br>
 src/compositor-rdp.c |  28 +++++++------<br>
 src/compositor.c     | 109 +++++++++++++++++++++++++++++++++++++++++++++++----<br>
 src/compositor.h     |  13 +++++-<br>
 src/shell.c          |  12 +++---<br>
 4 files changed, 135 insertions(+), 27 deletions(-)<br>
<br>
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c<br>
index 642a6b7..80b340d 100644<br>
--- a/src/compositor-rdp.c<br>
+++ b/src/compositor-rdp.c<br>
@@ -372,9 +372,10 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {<br>
        if(local_mode == output->current_mode)<br>
                return 0;<br>
<br>
-       output->current_mode->flags = 0;<br>
+       output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;<br>
+<br>
        output->current_mode = local_mode;<br>
-       output->current_mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;<br>
+       output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;<br>
<br>
        pixman_renderer_output_destroy(output);<br>
        pixman_renderer_output_create(output);<br>
@@ -466,7 +467,7 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,<br>
                goto out_free_output_and_modes;<br>
        }<br>
<br>
-       output->base.current_mode = currentMode;<br>
+       output->base.current_mode = output->base.native_mode = currentMode;<br>
        weston_output_init(&output->base, &c->base, 0, 0, width, height,<br>
                           WL_OUTPUT_TRANSFORM_NORMAL, 1);<br>
<br>
@@ -679,23 +680,26 @@ xf_peer_post_connect(freerdp_peer* client)<br>
        output = c->output;<br>
        settings = client->settings;<br>
<br>
-       if(!settings->SurfaceCommandsEnabled) {<br>
+       if (!settings->SurfaceCommandsEnabled) {<br>
                weston_log("client doesn't support required SurfaceCommands\n");<br>
                return FALSE;<br>
        }<br>
<br>
-       if(output->base.width != (int)settings->DesktopWidth ||<br>
+       if (output->base.width != (int)settings->DesktopWidth ||<br>
                        output->base.height != (int)settings->DesktopHeight)<br>
        {<br>
-               if(!settings->DesktopResize) {<br>
-                       weston_log("client don't support desktopResize()\n");<br>
+               struct weston_mode new_mode;<br>
+               struct weston_mode *target_mode;<br>
+               new_mode.width = (int)settings->DesktopWidth;<br>
+               new_mode.height = (int)settings->DesktopHeight;<br>
+               target_mode = find_matching_mode(&output->base, &new_mode);<br>
+               if (!target_mode) {<br>
+                       weston_log("client mode not found\n");<br>
                        return FALSE;<br>
                }<br>
-<br>
-               /* force the client size */<br>
-               settings->DesktopWidth = output->base.width;<br>
-               settings->DesktopHeight = output->base.height;<br>
-               client->update->DesktopResize(client->context);<br>
+               weston_output_switch_mode(&output->base, target_mode, 1, WESTON_MODE_SWITCH_SET_NATIVE);<br>
+               output->base.width = new_mode.width;<br>
+               output->base.height = new_mode.height;<br>
        }<br>
<br>
        weston_log("kbd_layout:%x kbd_type:%x kbd_subType:%x kbd_functionKeys:%x\n",<br>
diff --git a/src/compositor.c b/src/compositor.c<br>
index 4787857..d6ec316 100644<br>
--- a/src/compositor.c<br>
+++ b/src/compositor.c<br>
@@ -96,20 +96,88 @@ static void<br>
 weston_compositor_build_surface_list(struct weston_compositor *compositor);<br>
<br>
 WL_EXPORT int<br>
-weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale)<br>
+weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,<br>
+               int32_t scale, enum weston_mode_switch_op op)<br>
 {<br>
        struct weston_seat *seat;<br>
+       struct wl_resource *resource;<br>
        pixman_region32_t old_output_region;<br>
-       int ret;<br>
+       struct weston_mode old_mode;<br>
+       int ret, notify_mode_changed, notify_scale_changed;<br>
+       int fullscreen_mode, fullscreen_scale;<br>
<br>
        if (!output->switch_mode)<br>
                return -1;<br>
<br>
-       ret = output->switch_mode(output, mode);<br>
-       if (ret < 0)<br>
-               return ret;<br>
+       fullscreen_mode = (output->current_mode != output->original_mode);<br>
+       fullscreen_scale = (output->current_scale != output->original_scale);<br>
+       ret = 0;<br>
+<br>
+       notify_mode_changed = 0;<br>
+       notify_scale_changed = 0;<br>
+       switch(op) {<br>
+       case WESTON_MODE_SWITCH_SET_NATIVE:<br>
+               old_mode.width = output->native_mode->width;<br>
+               old_mode.height = output->native_mode->height;<br>
+               old_mode.refresh = output->native_mode->refresh;<br>
+               old_mode.flags = output->native_mode->flags;<br>
+<br>
+               output->native_mode = mode;<br>
+               if (!fullscreen_mode) {<br>
+                       notify_mode_changed = 1;<br>
+                       ret = output->switch_mode(output, mode);<br>
+                       if (ret < 0)<br>
+                               return ret;<br>
+               }<br>
+<br>
+               output->native_scale = scale;<br>
+               if(!fullscreen_scale) {<br>
+                       notify_scale_changed = 1;<br>
+               }<br>
+               break;<br>
+       case WESTON_MODE_SWITCH_SET_FULLSCREEN:<br>
+               if (!fullscreen_mode)<br>
+                       output->original_mode = output->native_mode;<br>
+               if (!fullscreen_scale)<br>
+                       output->original_scale = output->native_scale;<br>
+<br>
+               ret = output->switch_mode(output, mode);<br>
+               if (ret < 0)<br>
+                       return ret;<br>
+<br>
+               output->current_mode = mode;<br>
+               output->current_scale = scale;<br>
+               break;<br>
+       case WESTON_MODE_SWITCH_RESTORE_NATIVE:<br>
+               if (!fullscreen_mode) {<br>
+                       weston_log("already in the native mode\n");<br>
+                       return -1;<br>
+               }<br>
<br>
-        output->current_scale = scale;<br>
+               if (output->original_mode != output->native_mode) {<br>
+                       notify_mode_changed = 1;<br>
+                       old_mode.width = output->original_mode->width;<br>
+                       old_mode.height = output->original_mode->height;<br>
+                       old_mode.refresh = output->original_mode->refresh;<br>
+                       old_mode.flags = output->original_mode->flags;<br>
+                       output->original_mode = output->native_mode;<br>
+               }<br>
+<br>
+               ret = output->switch_mode(output, mode);<br>
+               if (ret < 0)<br>
+                       return ret;<br>
+<br>
+               if (output->original_scale != output->native_scale) {<br>
+                       notify_scale_changed = 1;<br>
+                       scale = output->native_scale;<br>
+               }<br>
+<br>
+               output->current_scale = output->native_scale;<br>
+               break;<br>
+       default:<br>
+               weston_log("unknown weston_switch_mode_op %d\n", op);<br>
+               break;<br>
+       }<br>
<br>
        pixman_region32_init(&old_output_region);<br>
        pixman_region32_copy(&old_output_region, &output->region);<br>
@@ -152,6 +220,31 @@ weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode<br>
<br>
        pixman_region32_fini(&old_output_region);<br>
<br>
+       /* notify clients of the changes */<br>
+       if (notify_mode_changed || notify_scale_changed) {<br>
+               wl_resource_for_each(resource, &output->resource_list) {<br>
+                       if(notify_mode_changed) {<br>
+                               wl_output_send_mode(resource,<br>
+                                               old_mode.flags & ~WL_OUTPUT_MODE_CURRENT,<br>
+                                               old_mode.width,<br>
+                                               old_mode.height,<br>
+                                               old_mode.refresh);<br>
+<br>
+                               wl_output_send_mode(resource,<br>
+                                               mode->flags | WL_OUTPUT_MODE_CURRENT,<br>
+                                               mode->width,<br>
+                                               mode->height,<br>
+                                               mode->refresh);<br>
+                       }<br>
+<br>
+                       if (notify_scale_changed)<br>
+                               wl_output_send_scale(resource, scale);<br>
+<br>
+                       if (wl_resource_get_version(resource) >= 2)<br>
+                                  wl_output_send_done(resource);<br>
+               }<br>
+       }<br>
+<br>
        return ret;<br>
 }<br>
<br>
@@ -1873,7 +1966,7 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)<br>
         * If this commit would cause the surface to move by the<br>
         * attach(dx, dy) parameters, the old damage region must be<br>
         * translated to correspond to the new surface coordinate system<br>
-        * origin.<br>
+        * original_mode.<br>
         */<br>
        pixman_region32_translate(&sub->cached.damage,<br>
                                  -surface->pending.sx, -surface-><a href="http://pending.sy" target="_blank">pending.sy</a>);<br>
@@ -2727,7 +2820,7 @@ weston_output_transform_scale_init(struct weston_output *output, uint32_t transf<br>
                break;<br>
        }<br>
<br>
-        output->current_scale = scale;<br>
+       output->native_scale = output->current_scale = scale;<br>
        output->width /= scale;<br>
        output->height /= scale;<br>
 }<br>
diff --git a/src/compositor.h b/src/compositor.h<br>
index 49365fd..7d6b059 100644<br>
--- a/src/compositor.h<br>
+++ b/src/compositor.h<br>
@@ -172,6 +172,12 @@ enum dpms_enum {<br>
        WESTON_DPMS_OFF<br>
 };<br>
<br>
+enum weston_mode_switch_op {<br>
+       WESTON_MODE_SWITCH_SET_NATIVE,<br>
+       WESTON_MODE_SWITCH_SET_FULLSCREEN,<br>
+       WESTON_MODE_SWITCH_RESTORE_NATIVE<br>
+};<br>
+<br>
 struct weston_output {<br>
        uint32_t id;<br>
        char *name;<br>
@@ -201,11 +207,13 @@ struct weston_output {<br>
        char *make, *model, *serial_number;<br>
        uint32_t subpixel;<br>
        uint32_t transform;<br>
+       int32_t native_scale;<br>
        int32_t current_scale;<br>
+       int32_t original_scale;<br>
<br>
+       struct weston_mode *native_mode;<br>
        struct weston_mode *current_mode;<br>
        struct weston_mode *original_mode;<br>
-       int32_t original_scale;<br>
        struct wl_list mode_list;<br>
<br>
        void (*start_repaint_loop)(struct weston_output *output);<br>
@@ -1207,7 +1215,8 @@ void<br>
 weston_surface_destroy(struct weston_surface *surface);<br>
<br>
 int<br>
-weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode, int32_t scale);<br>
+weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode,<br>
+                       int32_t scale, enum weston_mode_switch_op op);<br>
<br>
 int<br>
 noop_renderer_init(struct weston_compositor *ec);<br>
diff --git a/src/shell.c b/src/shell.c<br>
index cd94aa5..fca4f3c 100644<br>
--- a/src/shell.c<br>
+++ b/src/shell.c<br>
@@ -1624,11 +1624,12 @@ get_default_output(struct weston_compositor *compositor)<br>
 static void<br>
 restore_output_mode(struct weston_output *output)<br>
 {<br>
-       if (output->current != output->origin ||<br>
-           (int32_t)output->scale != output->origin_scale)<br>
+       if (output->current_mode != output->original_mode ||<br>
+           (int32_t)output->current_scale != output->original_scale)<br>
                weston_output_switch_mode(output,<br>
-                                         output->origin,<br>
-                                         output->origin_scale);<br>
+                                         output->original_mode,<br>
+                                         output->original_scale,<br>
+                                         WESTON_MODE_SWITCH_RESTORE_NATIVE);<br>
 }<br>
<br>
 static void<br>
@@ -1955,7 +1956,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)<br>
                                surf_height * surface->buffer_scale,<br>
                                shsurf->fullscreen.framerate};<br>
<br>
-                       if (weston_output_switch_mode(output, &mode, surface->buffer_scale) == 0) {<br>
+                       if (weston_output_switch_mode(output, &mode, surface->buffer_scale,<br>
+                                       WESTON_MODE_SWITCH_SET_FULLSCREEN) == 0) {<br>
                                weston_surface_set_position(surface,<br>
                                                            output->x - surf_x,<br>
                                                            output->y - surf_y);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.1.2<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>