Commit bddfcd07 authored by Alexandros Frantzis's avatar Alexandros Frantzis Committed by Alexandre Julliard

winewayland.drv: Infer and report Windows monitor positions.

Use the xdg-output-unstable-v1 protocol to get the size of the Wayland outputs in the compositor logical space, and use this information, along with the logical position and size in physical pixels (i.e., the current mode) to infer the Windows virtual screen coordinates of the monitors. Note that there are multiple possible mappings from Wayland logical coordinates to Windows virtual screen coordinates. We choose one algorithm that works well for the majority of output arrangements, and we can refine in the future as needed. Signed-off-by: 's avatarAlexandros Frantzis <alexandros.frantzis@collabora.com>
parent ce6a7ae8
......@@ -63,18 +63,128 @@ static int output_info_cmp_primary_x_y(const void *va, const void *vb)
return strcmp(a->output->name, b->output->name);
}
static inline BOOL output_info_overlap(struct output_info *a, struct output_info *b)
{
return b->x < a->x + a->output->current_mode->width &&
b->x + b->output->current_mode->width > a->x &&
b->y < a->y + a->output->current_mode->height &&
b->y + b->output->current_mode->height > a->y;
}
/* Map a point to one of the four quadrants of our 2d coordinate space:
* 0: bottom right (x >= 0, y >= 0)
* 1: top right (x >= 0, y < 0)
* 2: bottom left (x < 0, y >= 0)
* 3: top left (x < 0, y < 0) */
static inline int point_to_quadrant(int x, int y)
{
return (x < 0) * 2 + (y < 0);
}
/* Decide which of two outputs to keep stationary in order
* to resolve an overlap. */
static struct output_info *output_info_get_overlap_anchor(struct output_info *a,
struct output_info *b)
{
/* Preferences for the direction of growth in each quadrant, with a
* lower value signifying a higher preference. */
static const int quadrant_prefs[4][4] =
{
{0, 1, 2, 3}, /* quadrant 0 */
{3, 0, 2, 1}, /* quadrant 1 */
{2, 3, 0, 1}, /* quadrant 2 */
{3, 2, 1, 0}, /* quadrant 3 */
};
int qa = point_to_quadrant(a->output->logical_x, a->output->logical_y);
int qb = point_to_quadrant(b->output->logical_x, b->output->logical_y);
/* Direction of growth if a is the anchor. */
int qab = point_to_quadrant(b->output->logical_x - a->output->logical_x,
b->output->logical_y - a->output->logical_y);
/* Direction of growth if b is the anchor. */
int qba = point_to_quadrant(a->output->logical_x - b->output->logical_x,
a->output->logical_y - b->output->logical_y);
/* If the two output origins are in different quadrants, use the output
* in the lower valued quadrant as the anchor (so effectively outputs
* grow/move away from quadrant 0). */
if (qa != qb) return (qa < qb) ? a : b;
/* If the outputs are in the same quadrant, use the preference for the
* direction of growth in that quadrant to select the anchor. Again the
* intended effect is to grow/move outputs away from the origin. */
return (quadrant_prefs[qa][qab] < quadrant_prefs[qa][qba]) ? a : b;
}
static BOOL output_info_array_resolve_overlaps(struct wl_array *output_info_array)
{
struct output_info *a, *b;
BOOL found_overlap = FALSE;
wl_array_for_each(a, output_info_array)
{
wl_array_for_each(b, output_info_array)
{
struct output_info *anchor, *move;
BOOL x_use_end, y_use_end;
double rel_x, rel_y;
/* Break if we reach the same output in the inner loop, so that we
* don't process output pairs twice (since order doesn't matter for
* our algorithm.) */
if (a == b) break;
if (!output_info_overlap(a, b)) continue;
found_overlap = TRUE;
/* Decide which output to move to resolve the overlap. */
anchor = output_info_get_overlap_anchor(a, b);
move = anchor == a ? b : a;
/* Move the selected output on the X axis to resolve the overlap,
* while maintaining the same relative positioning of the outputs as
* the one they have in logical space. Use either the start or end
* of the moved output as the point to maintain the relative
* position of, depending on whether the anchor is before or after
* the moved output on the axis. */
x_use_end = move->output->logical_x < anchor->output->logical_x;
rel_x = (move->output->logical_x - anchor->output->logical_x +
(x_use_end ? move->output->logical_w : 0)) /
(double)anchor->output->logical_w;
move->x = anchor->x + anchor->output->current_mode->width * rel_x -
(x_use_end ? move->output->current_mode->width : 0);
/* Similarly for the Y axis. */
y_use_end = move->output->logical_y < anchor->output->logical_y;
rel_y = (move->output->logical_y - anchor->output->logical_y +
(y_use_end ? move->output->logical_h : 0)) /
(double)anchor->output->logical_h;
move->y = anchor->y + anchor->output->current_mode->height * rel_y -
(y_use_end ? move->output->current_mode->height : 0);
}
}
return found_overlap;
}
static void output_info_array_arrange_physical_coords(struct wl_array *output_info_array)
{
struct output_info *info;
size_t num_outputs = output_info_array->size / sizeof(struct output_info);
int steps = 0;
/* Set physical pixel coordinates. */
/* Set the initial physical pixel coordinates. */
wl_array_for_each(info, output_info_array)
{
info->x = info->output->logical_x;
info->y = info->output->logical_y;
}
/* Try to iteratively resolve overlaps, but be defensive and set an upper
* iteration bound to ensure we avoid infinite loops. */
while (output_info_array_resolve_overlaps(output_info_array) &&
++steps < num_outputs)
continue;
/* Now that we have our physical pixel coordinates, sort from physical left
* to right, but ensure the primary output is first. */
qsort(output_info_array->data, num_outputs, sizeof(struct output_info),
......
......@@ -101,8 +101,9 @@ static void wayland_output_done(struct wayland_output *output)
{
struct wayland_output_mode *mode;
TRACE("name=%s logical=%d,%d\n",
output->name, output->logical_x, output->logical_y);
TRACE("name=%s logical=%d,%d+%dx%d\n",
output->name, output->logical_x, output->logical_y,
output->logical_w, output->logical_h);
RB_FOR_EACH_ENTRY(mode, &output->modes, struct wayland_output_mode, entry)
{
......@@ -173,6 +174,10 @@ static void zxdg_output_v1_handle_logical_size(void *data,
int32_t width,
int32_t height)
{
struct wayland_output *output = data;
TRACE("logical_w=%d logical_h=%d\n", width, height);
output->logical_w = width;
output->logical_h = height;
}
static void zxdg_output_v1_handle_done(void *data,
......
......@@ -71,6 +71,7 @@ struct wayland_output
struct wayland_output_mode *current_mode;
char *name;
int logical_x, logical_y;
int logical_w, logical_h;
uint32_t global_id;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment