diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 614ce8fe6e1..3f9c052f2b0 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) -UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) +UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(PTHREAD_LIBS) SOURCES = \ display.c \ diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index f734c1714fa..ebe151ffab0 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -50,7 +50,7 @@ void wayland_init_display_devices(BOOL force) struct output_info { int x, y; - struct wayland_output *output; + struct wayland_output_state *output; }; static int output_info_cmp_primary_x_y(const void *va, const void *vb) @@ -298,11 +298,13 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage wl_array_init(&output_info_array); + pthread_mutex_lock(&process_wayland.output_mutex); + wl_list_for_each(output, &process_wayland.output_list, link) { - if (!output->current_mode) continue; + if (!output->current.current_mode) continue; output_info = wl_array_add(&output_info_array, sizeof(*output_info)); - if (output_info) output_info->output = output; + if (output_info) output_info->output = &output->current; else ERR("Failed to allocate space for output_info\n"); } @@ -321,5 +323,7 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage wl_array_release(&output_info_array); + pthread_mutex_unlock(&process_wayland.output_mutex); + return TRUE; } diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 38c53e280c5..34aa8bec04e 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -34,7 +34,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); struct wayland process_wayland = { - .output_list = {&process_wayland.output_list, &process_wayland.output_list} + .output_list = {&process_wayland.output_list, &process_wayland.output_list}, + .output_mutex = PTHREAD_MUTEX_INITIALIZER }; /********************************************************************** @@ -77,7 +78,7 @@ static void registry_handle_global_remove(void *data, struct wl_registry *regist { if (output->global_id == id) { - TRACE("removing output->name=%s\n", output->name); + TRACE("removing output->name=%s\n", output->current.name); wayland_output_destroy(output); return; } diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index 8293f43b56f..5ea04340347 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -35,6 +35,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); static const int32_t default_refresh = 60000; static uint32_t next_output_id = 0; +#define WAYLAND_OUTPUT_CHANGED_MODES 0x01 +#define WAYLAND_OUTPUT_CHANGED_NAME 0x02 +#define WAYLAND_OUTPUT_CHANGED_LOGICAL_XY 0x04 +#define WAYLAND_OUTPUT_CHANGED_LOGICAL_WH 0x08 + /********************************************************************** * Output handling */ @@ -62,9 +67,9 @@ static int wayland_output_mode_cmp_rb(const void *key, return 0; } -static void wayland_output_add_mode(struct wayland_output *output, - int32_t width, int32_t height, - int32_t refresh, BOOL current) +static void wayland_output_state_add_mode(struct wayland_output_state *state, + int32_t width, int32_t height, + int32_t refresh, BOOL current) { struct rb_entry *mode_entry; struct wayland_output_mode *mode; @@ -75,7 +80,7 @@ static void wayland_output_add_mode(struct wayland_output *output, .refresh = refresh, }; - mode_entry = rb_get(&output->modes, &key); + mode_entry = rb_get(&state->modes, &key); if (mode_entry) { mode = RB_ENTRY_VALUE(mode_entry, struct wayland_output_mode, entry); @@ -91,10 +96,10 @@ static void wayland_output_add_mode(struct wayland_output *output, mode->width = width; mode->height = height; mode->refresh = refresh; - rb_put(&output->modes, mode, &mode->entry); + rb_put(&state->modes, mode, &mode->entry); } - if (current) output->current_mode = mode; + if (current) state->current_mode = mode; } static void maybe_init_display_devices(void) @@ -117,19 +122,65 @@ static void maybe_init_display_devices(void) wayland_init_display_devices(TRUE); } +static void wayland_output_mode_free_rb(struct rb_entry *entry, void *ctx) +{ + free(RB_ENTRY_VALUE(entry, struct wayland_output_mode, entry)); +} + static void wayland_output_done(struct wayland_output *output) { struct wayland_output_mode *mode; - TRACE("name=%s logical=%d,%d+%dx%d\n", - output->name, output->logical_x, output->logical_y, - output->logical_w, output->logical_h); + /* Update current state from pending state. */ + pthread_mutex_lock(&process_wayland.output_mutex); - RB_FOR_EACH_ENTRY(mode, &output->modes, struct wayland_output_mode, entry) + if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_MODES) + { + RB_FOR_EACH_ENTRY(mode, &output->pending.modes, struct wayland_output_mode, entry) + { + wayland_output_state_add_mode(&output->current, + mode->width, mode->height, mode->refresh, + mode == output->pending.current_mode); + } + rb_destroy(&output->pending.modes, wayland_output_mode_free_rb, NULL); + rb_init(&output->pending.modes, wayland_output_mode_cmp_rb); + } + + if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_NAME) + { + free(output->current.name); + output->current.name = output->pending.name; + output->pending.name = NULL; + } + + if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_LOGICAL_XY) + { + output->current.logical_x = output->pending.logical_x; + output->current.logical_y = output->pending.logical_y; + } + + if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_LOGICAL_WH) + { + output->current.logical_w = output->pending.logical_w; + output->current.logical_h = output->pending.logical_h; + } + + if (wl_list_empty(&output->link)) + wl_list_insert(process_wayland.output_list.prev, &output->link); + + output->pending_flags = 0; + + pthread_mutex_unlock(&process_wayland.output_mutex); + + TRACE("name=%s logical=%d,%d+%dx%d\n", + output->current.name, output->current.logical_x, output->current.logical_y, + output->current.logical_w, output->current.logical_h); + + RB_FOR_EACH_ENTRY(mode, &output->current.modes, struct wayland_output_mode, entry) { TRACE("mode %dx%d @ %d %s\n", mode->width, mode->height, mode->refresh, - output->current_mode == mode ? "*" : ""); + output->current.current_mode == mode ? "*" : ""); } maybe_init_display_devices(); @@ -153,8 +204,10 @@ static void output_handle_mode(void *data, struct wl_output *wl_output, /* Windows apps don't expect a zero refresh rate, so use a default value. */ if (refresh == 0) refresh = default_refresh; - wayland_output_add_mode(output, width, height, refresh, - (flags & WL_OUTPUT_MODE_CURRENT)); + wayland_output_state_add_mode(&output->pending, width, height, refresh, + (flags & WL_OUTPUT_MODE_CURRENT)); + + output->pending_flags |= WAYLAND_OUTPUT_CHANGED_MODES; } static void output_handle_done(void *data, struct wl_output *wl_output) @@ -187,8 +240,9 @@ static void zxdg_output_v1_handle_logical_position(void *data, { struct wayland_output *output = data; TRACE("logical_x=%d logical_y=%d\n", x, y); - output->logical_x = x; - output->logical_y = y; + output->pending.logical_x = x; + output->pending.logical_y = y; + output->pending_flags |= WAYLAND_OUTPUT_CHANGED_LOGICAL_XY; } static void zxdg_output_v1_handle_logical_size(void *data, @@ -198,8 +252,9 @@ static void zxdg_output_v1_handle_logical_size(void *data, { struct wayland_output *output = data; TRACE("logical_w=%d logical_h=%d\n", width, height); - output->logical_w = width; - output->logical_h = height; + output->pending.logical_w = width; + output->pending.logical_h = height; + output->pending_flags |= WAYLAND_OUTPUT_CHANGED_LOGICAL_WH; } static void zxdg_output_v1_handle_done(void *data, @@ -218,8 +273,9 @@ static void zxdg_output_v1_handle_name(void *data, { struct wayland_output *output = data; - free(output->name); - output->name = strdup(name); + free(output->pending.name); + output->pending.name = strdup(name); + output->pending_flags |= WAYLAND_OUTPUT_CHANGED_NAME; } static void zxdg_output_v1_handle_description(void *data, @@ -259,14 +315,15 @@ 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); - rb_init(&output->modes, wayland_output_mode_cmp_rb); + rb_init(&output->pending.modes, wayland_output_mode_cmp_rb); + rb_init(&output->current.modes, wayland_output_mode_cmp_rb); /* Have a fallback while we don't have compositor given name. */ name_len = snprintf(NULL, 0, "WaylandOutput%d", next_output_id); - output->name = malloc(name_len + 1); - if (output->name) + output->current.name = malloc(name_len + 1); + if (output->current.name) { - snprintf(output->name, name_len + 1, "WaylandOutput%d", next_output_id++); + snprintf(output->current.name, name_len + 1, "WaylandOutput%d", next_output_id++); } else { @@ -277,8 +334,6 @@ BOOL wayland_output_create(uint32_t id, uint32_t version) if (process_wayland.zxdg_output_manager_v1) wayland_output_use_xdg_extension(output); - wl_list_insert(process_wayland.output_list.prev, &output->link); - return TRUE; err: @@ -286,9 +341,10 @@ err: return FALSE; } -static void wayland_output_mode_free_rb(struct rb_entry *entry, void *ctx) +static void wayland_output_state_deinit(struct wayland_output_state *state) { - free(RB_ENTRY_VALUE(entry, struct wayland_output_mode, entry)); + rb_destroy(&state->modes, wayland_output_mode_free_rb, NULL); + free(state->name); } /********************************************************************** @@ -298,12 +354,15 @@ static void wayland_output_mode_free_rb(struct rb_entry *entry, void *ctx) */ void wayland_output_destroy(struct wayland_output *output) { - rb_destroy(&output->modes, wayland_output_mode_free_rb, NULL); + pthread_mutex_lock(&process_wayland.output_mutex); wl_list_remove(&output->link); + pthread_mutex_unlock(&process_wayland.output_mutex); + + wayland_output_state_deinit(&output->pending); + wayland_output_state_deinit(&output->current); if (output->zxdg_output_v1) zxdg_output_v1_destroy(output->zxdg_output_v1); wl_output_destroy(output->wl_output); - free(output->name); free(output); maybe_init_display_devices(); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 95d115113b3..600fcfce355 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -25,6 +25,7 @@ # error You must include config.h to use this header #endif +#include #include #include "xdg-output-unstable-v1-client-protocol.h" @@ -53,6 +54,8 @@ struct wayland struct wl_registry *wl_registry; struct zxdg_output_manager_v1 *zxdg_output_manager_v1; struct wl_list output_list; + /* Protects the output_list and the wayland_output.current states. */ + pthread_mutex_t output_mutex; }; struct wayland_output_mode @@ -63,17 +66,24 @@ struct wayland_output_mode int32_t refresh; }; -struct wayland_output +struct wayland_output_state { - struct wl_list link; - struct wl_output *wl_output; - struct zxdg_output_v1 *zxdg_output_v1; struct rb_tree modes; struct wayland_output_mode *current_mode; char *name; int logical_x, logical_y; int logical_w, logical_h; +}; + +struct wayland_output +{ + struct wl_list link; + struct wl_output *wl_output; + struct zxdg_output_v1 *zxdg_output_v1; uint32_t global_id; + unsigned int pending_flags; + struct wayland_output_state pending; + struct wayland_output_state current; }; /**********************************************************************