From: Alexandros Frantzis alexandros.frantzis@collabora.com
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/display.c | 23 +++++--- dlls/winewayland.drv/wayland_output.c | 81 ++++++++++++++++++++++++--- dlls/winewayland.drv/waylanddrv.h | 4 +- 3 files changed, 91 insertions(+), 17 deletions(-)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index 74e6450a42b..991de498aa5 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -90,8 +90,8 @@ static void wayland_add_device_monitor(const struct gdi_device_manager *device_m struct gdi_monitor monitor = {0};
SetRect(&monitor.rc_monitor, 0, 0, - output->current_mode.width, - output->current_mode.height); + output->current_mode->width, + output->current_mode->height);
/* We don't have a direct way to get the work area in Wayland. */ monitor.rc_work = monitor.rc_monitor; @@ -117,12 +117,17 @@ static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW * mode->dmDisplayFrequency = output_mode->refresh / 1000; }
-static void wayland_add_device_mode(const struct gdi_device_manager *device_manager, - void *param, struct wayland_output *output) +static void wayland_add_device_modes(const struct gdi_device_manager *device_manager, + void *param, struct wayland_output *output) { - DEVMODEW mode; - populate_devmode(&output->current_mode, &mode); - device_manager->add_mode(&mode, param); + struct wayland_output_mode *output_mode; + + wl_list_for_each(output_mode, &output->mode_list, link) + { + DEVMODEW mode; + populate_devmode(output_mode, &mode); + device_manager->add_mode(&mode, param); + } }
/*********************************************************************** @@ -145,10 +150,10 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
wl_list_for_each(output, &wayland->output_list, link) { - if (!output->current_mode.refresh) continue; + if (!output->current_mode) continue; wayland_add_device_adapter(device_manager, param, output_id); wayland_add_device_monitor(device_manager, param, output); - wayland_add_device_mode(device_manager, param, output); + wayland_add_device_modes(device_manager, param, output); output_id++; }
diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index 61a0fe99342..bbbffaa09a9 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -38,6 +38,61 @@ static const int32_t default_refresh = 60000; * Output handling */
+/* Compare mode with the set of provided mode parameters and return -1 if the + * mode compares less than the parameters, 0 if the mode compares equal to the + * parameters, and 1 if the mode compares greater than the parameters. + * + * The comparison is based on comparing the width, height and refresh + * in that order. + */ +static int wayland_output_mode_cmp(struct wayland_output_mode *mode, + int32_t width, int32_t height, + int32_t refresh) +{ + if (mode->width < width) return -1; + if (mode->width > width) return 1; + if (mode->height < height) return -1; + if (mode->height > height) return 1; + if (mode->refresh < refresh) return -1; + if (mode->refresh > refresh) return 1; + return 0; +} + +static void wayland_output_add_mode(struct wayland_output *output, + int32_t width, int32_t height, + int32_t refresh, BOOL current) +{ + struct wayland_output_mode *mode; + struct wl_list *insert_after_link = output->mode_list.prev; + + /* Update mode if it's already in list, otherwise find the insertion point + * to maintain the sorted order. */ + wl_list_for_each(mode, &output->mode_list, link) + { + int cmp = wayland_output_mode_cmp(mode, width, height, refresh); + if (cmp == 0) /* mode == new */ + { + if (current) output->current_mode = mode; + return; + } + else if (cmp == 1) /* mode > new */ + { + insert_after_link = mode->link.prev; + break; + } + } + + mode = calloc(1, sizeof(*mode)); + + mode->width = width; + mode->height = height; + mode->refresh = refresh; + + if (current) output->current_mode = mode; + + wl_list_insert(insert_after_link, &mode->link); +} + static void output_handle_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, @@ -53,22 +108,26 @@ static void output_handle_mode(void *data, struct wl_output *wl_output, { struct wayland_output *output = data;
- if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; - /* Windows apps don't expect a zero refresh rate, so use a default value. */ if (refresh == 0) refresh = default_refresh;
- output->current_mode.width = width; - output->current_mode.height = width; - output->current_mode.refresh = refresh; + wayland_output_add_mode(output, width, height, refresh, + (flags & WL_OUTPUT_MODE_CURRENT)); }
static void output_handle_done(void *data, struct wl_output *wl_output) { struct wayland_output *output = data; + struct wayland_output_mode *mode;
- TRACE("output->name=%s mode=%dx%d\n", - output->name, output->current_mode.width, output->current_mode.height); + TRACE("output->name=%s\n", output->name); + + wl_list_for_each(mode, &output->mode_list, link) + { + TRACE("mode %dx%d @ %d %s\n", + mode->width, mode->height, mode->refresh, + output->current_mode == mode ? "*" : ""); + }
wayland_init_display_devices(); } @@ -107,6 +166,7 @@ BOOL wayland_output_create(uint32_t id, uint32_t version) wl_output_add_listener(output->wl_output, &output_listener, output);
wl_list_init(&output->link); + wl_list_init(&output->mode_list);
output->name = malloc(20); if (output->name) @@ -136,6 +196,13 @@ err: */ void wayland_output_destroy(struct wayland_output *output) { + struct wayland_output_mode *mode, *tmp; + + wl_list_for_each_safe(mode, tmp, &output->mode_list, link) + { + wl_list_remove(&mode->link); + free(mode); + } wl_list_remove(&output->link); free(output->name); wl_output_destroy(output->wl_output); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 462706bebad..4a04e9f07a9 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -54,6 +54,7 @@ struct wayland
struct wayland_output_mode { + struct wl_list link; int32_t width; int32_t height; int32_t refresh; @@ -63,7 +64,8 @@ struct wayland_output { struct wl_list link; struct wl_output *wl_output; - struct wayland_output_mode current_mode; + struct wl_list mode_list; + struct wayland_output_mode *current_mode; char *name; uint32_t global_id; };