From 57388e44e5a8ddd01f44602d5d24514977f21bd1 Mon Sep 17 00:00:00 2001 From: Hardening Date: Wed, 18 Sep 2013 23:56:36 +0200 Subject: [PATCH] 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. --- 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 916fd5f2..ef92531a 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -1944,7 +1944,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 e592fe5d..f0625cdf 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 3761be1b..2a0b0c3e 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 642a6b72..69f1d044 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 afca44cc..7c5ed0e6 100644 --- a/src/compositor-rpi.c +++ b/src/compositor-rpi.c @@ -370,7 +370,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 4caad81c..2b8b9562 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 1dd5037d..704e751e 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 50ec7392..e138e997 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 a7435bf4..8ac54805 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 c1e0109e..d1847f53 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);