From: Alexandros Frantzis alexandros.frantzis@collabora.com
Use the xdg-output-unstable-v1 protocol to get the positions of the Wayland outputs in the compositor logical space, and use this information to arrange the monitors in the Windows virtual screen space. For now we assume that the logical positions match the physical pixel positions (i.e., the outputs are not scaled), a deficiency which will be addressed in an upcoming commit.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/display.c | 88 +++++++++++++++++++++++---- dlls/winewayland.drv/wayland_output.c | 7 ++- dlls/winewayland.drv/waylanddrv.h | 1 + 3 files changed, 83 insertions(+), 13 deletions(-)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index 2a5c86e2d8c..fd87b088ba9 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -30,6 +30,8 @@
#include "ntuser.h"
+#include <stdlib.h> + WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
static BOOL force_display_devices_refresh; @@ -47,6 +49,46 @@ void wayland_init_display_devices(void) wayland_refresh_display_devices(); }
+struct output_info +{ + int x, y; + struct wayland_output *output; +}; + +static int output_info_cmp_primary_x_y(const void *va, const void *vb) +{ + const struct output_info *a = va; + const struct output_info *b = vb; + BOOL a_is_primary = a->x == 0 && a->y == 0; + BOOL b_is_primary = b->x == 0 && b->y == 0; + + if (a_is_primary && !b_is_primary) return -1; + if (!a_is_primary && b_is_primary) return 1; + if (a->x < b->x) return -1; + if (a->x > b->x) return 1; + if (a->y < b->y) return -1; + if (a->y > b->y) return 1; + return 0; +} + +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); + + /* Set physical pixel coordinates. */ + wl_array_for_each(info, output_info_array) + { + info->x = info->output->logical_x; + info->y = info->output->logical_y; + } + + /* 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), + output_info_cmp_primary_x_y); +} + static void wayland_add_device_gpu(const struct gdi_device_manager *device_manager, void *param) { @@ -76,13 +118,13 @@ static void wayland_add_device_adapter(const struct gdi_device_manager *device_m }
static void wayland_add_device_monitor(const struct gdi_device_manager *device_manager, - void *param, struct wayland_output *output) + void *param, struct output_info *output_info) { struct gdi_monitor monitor = {0};
- SetRect(&monitor.rc_monitor, 0, 0, - output->current_mode->width, - output->current_mode->height); + SetRect(&monitor.rc_monitor, output_info->x, output_info->y, + output_info->x + output_info->output->current_mode->width, + output_info->y + output_info->output->current_mode->height);
/* We don't have a direct way to get the work area in Wayland. */ monitor.rc_work = monitor.rc_monitor; @@ -90,7 +132,7 @@ static void wayland_add_device_monitor(const struct gdi_device_manager *device_m monitor.state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE;
TRACE("name=%s rc_monitor=rc_work=%s state_flags=0x%x\n", - output->name, wine_dbgstr_rect(&monitor.rc_monitor), + output_info->output->name, wine_dbgstr_rect(&monitor.rc_monitor), (UINT)monitor.state_flags);
device_manager->add_monitor(&monitor, param); @@ -109,16 +151,22 @@ static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW * }
static void wayland_add_device_modes(const struct gdi_device_manager *device_manager, - void *param, struct wayland_output *output) + void *param, struct output_info *output_info) { struct wayland_output_mode *output_mode;
- RB_FOR_EACH_ENTRY(output_mode, &output->modes, struct wayland_output_mode, entry) + RB_FOR_EACH_ENTRY(output_mode, &output_info->output->modes, + struct wayland_output_mode, entry) { DEVMODEW mode = {.dmSize = sizeof(mode)}; - BOOL mode_is_current = output_mode == output->current_mode; + BOOL mode_is_current = output_mode == output_info->output->current_mode; populate_devmode(output_mode, &mode); - if (mode_is_current) mode.dmFields |= DM_POSITION; + if (mode_is_current) + { + mode.dmFields |= DM_POSITION; + mode.dmPosition.x = output_info->x; + mode.dmPosition.y = output_info->y; + } device_manager->add_mode(&mode, mode_is_current, param); } } @@ -131,6 +179,8 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage { struct wayland_output *output; INT output_id = 0; + struct wl_array output_info_array; + struct output_info *output_info;
/* For now, update the display devices only when a compositor side update * is received in the desktop window process. */ @@ -140,16 +190,30 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
force_display_devices_refresh = FALSE;
- wayland_add_device_gpu(device_manager, param); + wl_array_init(&output_info_array);
wl_list_for_each(output, &process_wayland->output_list, link) { if (!output->current_mode) continue; + output_info = wl_array_add(&output_info_array, sizeof(*output_info)); + if (output_info) output_info->output = output; + else ERR("Failed to allocate space for output_info\n"); + } + + output_info_array_arrange_physical_coords(&output_info_array); + + /* Populate GDI devices. */ + wayland_add_device_gpu(device_manager, param); + + wl_array_for_each(output_info, &output_info_array) + { wayland_add_device_adapter(device_manager, param, output_id); - wayland_add_device_monitor(device_manager, param, output); - wayland_add_device_modes(device_manager, param, output); + wayland_add_device_monitor(device_manager, param, output_info); + wayland_add_device_modes(device_manager, param, output_info); output_id++; }
+ wl_array_release(&output_info_array); + return TRUE; } diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index 8eb24fe97f3..29f5411bba5 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -101,7 +101,8 @@ static void wayland_output_done(struct wayland_output *output) { struct wayland_output_mode *mode;
- TRACE("name=%s\n", output->name); + TRACE("name=%s logical=%d,%d\n", + output->name, output->logical_x, output->logical_y);
RB_FOR_EACH_ENTRY(mode, &output->modes, struct wayland_output_mode, entry) { @@ -163,6 +164,10 @@ static void zxdg_output_v1_handle_logical_position(void *data, int32_t x, int32_t y) { + struct wayland_output *output = data; + TRACE("logical_x=%d logical_y=%d\n", x, y); + output->logical_x = x; + output->logical_y = y; }
static void zxdg_output_v1_handle_logical_size(void *data, diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 98c31068f2f..7e606f45f78 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -70,6 +70,7 @@ struct wayland_output struct rb_tree modes; struct wayland_output_mode *current_mode; char *name; + int logical_x, logical_y; uint32_t global_id; };