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

Reply via email to