the output with most width will be selected as primary output. primary output occupy the first position in weston_compositor->output_list
if clone_output's height is larger than primary_output's height clone_output's mode should be changed, otherwise the setting mode for clone_output will fail. choose a nearest mode below primary_output's mode. Signed-off-by: Xiong Zhang <[email protected]> --- src/compositor-drm.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 1e2f3ab..8d16d29 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -1051,6 +1051,97 @@ drm_assign_planes(struct weston_output *output) pixman_region32_fini(&overlap); } +/* the output with maximum width is the primary output */ +static struct drm_output * +choose_output(struct drm_output *primary, + struct drm_output *clone) +{ + if (clone->base.current->width > primary->base.current->width) + primary = clone; + + return primary; +} + +/*if clone_output's height > primary_output's height */ +/*clone_output's mode shoulde be changed, or else set mode for clone_output */ +/*will fail. Choose a nearest mode below primary_output's current_mode */ +static void +adjust_clone_output_mode(struct drm_output *clone_output) +{ + struct drm_mode *mode, *choose_mode; + uint32_t multiple_delta, choose_delta; + struct weston_mode *current_mode; + + choose_mode = NULL; + choose_delta = 0xffffffff; + current_mode = clone_output->base.compositor->primary_output->current; + + wl_list_for_each(mode, &clone_output->base.mode_list, base.link) { + if (mode->mode_info.hdisplay <= current_mode->width && + mode->mode_info.vdisplay <= current_mode->height) { + if (mode->mode_info.hdisplay == current_mode->width) { + choose_mode = mode; + break; + } else if (mode->mode_info.vdisplay == current_mode->height) { + choose_mode = mode; + break; + } else { + multiple_delta = (current_mode->width - mode->mode_info.hdisplay) * + (current_mode->height - mode->mode_info.vdisplay); + if (multiple_delta < choose_delta) { + choose_delta = multiple_delta; + choose_mode = mode; + } + } + } + } + if (!choose_mode) { + weston_log("clone mode fail in chooseing mode for clone output\n"); + return; + } + clone_output->base.current->flags &= ~WL_OUTPUT_MODE_CURRENT; + clone_output->base.current = &choose_mode->base; + clone_output->base.current->flags |= WL_OUTPUT_MODE_CURRENT; +} + +static int +clone_output_need_adjust_mode(struct drm_output *clone_output) +{ + struct drm_output *primary_output; + + primary_output = (struct drm_output *)clone_output->base.compositor->primary_output; + if (clone_output->base.current->height > primary_output->base.current->height || + clone_output->base.current->width > primary_output->base.current->width) + return 1; + else + return 0; +} + +static void +clone_mode_add_output(struct drm_output *output) +{ + struct drm_compositor *ec = (struct drm_compositor *)output->base.compositor; + struct drm_output *origin_output; + + if (!ec->base.primary_output) { + ec->base.primary_output = &output->base; + return; + } else + origin_output = (struct drm_output *)ec->base.primary_output; + + if (choose_output(origin_output, output) != origin_output) { + /* make sure primary output is the first in output_list when clone mode is enabled */ + wl_list_remove(&output->base.link); + wl_list_insert(&ec->base.output_list, &output->base.link); + ec->base.primary_output = &output->base; + } else { + /* added output used as clone output, set it mode here */ + if (clone_output_need_adjust_mode(output)) + /*new added output need to adjust mode*/ + adjust_clone_output_mode(output); + } +} + static void drm_output_fini_pixman(struct drm_output *output); @@ -1939,6 +2030,8 @@ create_output_for_connector(struct drm_compositor *ec, } wl_list_insert(ec->base.output_list.prev, &output->base.link); + if (ec->base.multiscreen_mode == WESTON_MULTISCREEN_CLONE) + clone_mode_add_output(output); find_and_parse_output_edid(ec, output, connector); if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) @@ -2109,9 +2202,10 @@ create_outputs(struct drm_compositor *ec, uint32_t option_connector, continue; } - x += container_of(ec->base.output_list.prev, - struct weston_output, - link)->width; + if (ec->base.multiscreen_mode == WESTON_MULTISCREEN_EXTEND) + x += container_of(ec->base.output_list.prev, + struct weston_output, + link)->width; } drmModeFreeConnector(connector); -- 1.8.3.2 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
