mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-02 08:23:38 +00:00
winewayland.drv: Make access to Wayland output information thread-safe.
Store all incoming Wayland output state as pending and make it current in a thread-safe way when the "done" event arrives. This enables other threads, with proper locking, to safely read consistent and complete Wayland output information.
This commit is contained in:
parent
0031c3b46c
commit
1a336a259c
|
@ -1,7 +1,7 @@
|
||||||
MODULE = winewayland.drv
|
MODULE = winewayland.drv
|
||||||
UNIXLIB = winewayland.so
|
UNIXLIB = winewayland.so
|
||||||
UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS)
|
UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS)
|
||||||
UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS)
|
UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(PTHREAD_LIBS)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
display.c \
|
display.c \
|
||||||
|
|
|
@ -50,7 +50,7 @@ void wayland_init_display_devices(BOOL force)
|
||||||
struct output_info
|
struct output_info
|
||||||
{
|
{
|
||||||
int x, y;
|
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)
|
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);
|
wl_array_init(&output_info_array);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&process_wayland.output_mutex);
|
||||||
|
|
||||||
wl_list_for_each(output, &process_wayland.output_list, link)
|
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));
|
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");
|
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);
|
wl_array_release(&output_info_array);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&process_wayland.output_mutex);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
|
||||||
|
|
||||||
struct wayland process_wayland =
|
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)
|
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);
|
wayland_output_destroy(output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
|
||||||
static const int32_t default_refresh = 60000;
|
static const int32_t default_refresh = 60000;
|
||||||
static uint32_t next_output_id = 0;
|
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
|
* Output handling
|
||||||
*/
|
*/
|
||||||
|
@ -62,9 +67,9 @@ static int wayland_output_mode_cmp_rb(const void *key,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wayland_output_add_mode(struct wayland_output *output,
|
static void wayland_output_state_add_mode(struct wayland_output_state *state,
|
||||||
int32_t width, int32_t height,
|
int32_t width, int32_t height,
|
||||||
int32_t refresh, BOOL current)
|
int32_t refresh, BOOL current)
|
||||||
{
|
{
|
||||||
struct rb_entry *mode_entry;
|
struct rb_entry *mode_entry;
|
||||||
struct wayland_output_mode *mode;
|
struct wayland_output_mode *mode;
|
||||||
|
@ -75,7 +80,7 @@ static void wayland_output_add_mode(struct wayland_output *output,
|
||||||
.refresh = refresh,
|
.refresh = refresh,
|
||||||
};
|
};
|
||||||
|
|
||||||
mode_entry = rb_get(&output->modes, &key);
|
mode_entry = rb_get(&state->modes, &key);
|
||||||
if (mode_entry)
|
if (mode_entry)
|
||||||
{
|
{
|
||||||
mode = RB_ENTRY_VALUE(mode_entry, struct wayland_output_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->width = width;
|
||||||
mode->height = height;
|
mode->height = height;
|
||||||
mode->refresh = refresh;
|
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)
|
static void maybe_init_display_devices(void)
|
||||||
|
@ -117,19 +122,65 @@ static void maybe_init_display_devices(void)
|
||||||
wayland_init_display_devices(TRUE);
|
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)
|
static void wayland_output_done(struct wayland_output *output)
|
||||||
{
|
{
|
||||||
struct wayland_output_mode *mode;
|
struct wayland_output_mode *mode;
|
||||||
|
|
||||||
TRACE("name=%s logical=%d,%d+%dx%d\n",
|
/* Update current state from pending state. */
|
||||||
output->name, output->logical_x, output->logical_y,
|
pthread_mutex_lock(&process_wayland.output_mutex);
|
||||||
output->logical_w, output->logical_h);
|
|
||||||
|
|
||||||
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",
|
TRACE("mode %dx%d @ %d %s\n",
|
||||||
mode->width, mode->height, mode->refresh,
|
mode->width, mode->height, mode->refresh,
|
||||||
output->current_mode == mode ? "*" : "");
|
output->current.current_mode == mode ? "*" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_init_display_devices();
|
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. */
|
/* Windows apps don't expect a zero refresh rate, so use a default value. */
|
||||||
if (refresh == 0) refresh = default_refresh;
|
if (refresh == 0) refresh = default_refresh;
|
||||||
|
|
||||||
wayland_output_add_mode(output, width, height, refresh,
|
wayland_output_state_add_mode(&output->pending, width, height, refresh,
|
||||||
(flags & WL_OUTPUT_MODE_CURRENT));
|
(flags & WL_OUTPUT_MODE_CURRENT));
|
||||||
|
|
||||||
|
output->pending_flags |= WAYLAND_OUTPUT_CHANGED_MODES;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_handle_done(void *data, struct wl_output *wl_output)
|
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;
|
struct wayland_output *output = data;
|
||||||
TRACE("logical_x=%d logical_y=%d\n", x, y);
|
TRACE("logical_x=%d logical_y=%d\n", x, y);
|
||||||
output->logical_x = x;
|
output->pending.logical_x = x;
|
||||||
output->logical_y = y;
|
output->pending.logical_y = y;
|
||||||
|
output->pending_flags |= WAYLAND_OUTPUT_CHANGED_LOGICAL_XY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zxdg_output_v1_handle_logical_size(void *data,
|
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;
|
struct wayland_output *output = data;
|
||||||
TRACE("logical_w=%d logical_h=%d\n", width, height);
|
TRACE("logical_w=%d logical_h=%d\n", width, height);
|
||||||
output->logical_w = width;
|
output->pending.logical_w = width;
|
||||||
output->logical_h = height;
|
output->pending.logical_h = height;
|
||||||
|
output->pending_flags |= WAYLAND_OUTPUT_CHANGED_LOGICAL_WH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zxdg_output_v1_handle_done(void *data,
|
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;
|
struct wayland_output *output = data;
|
||||||
|
|
||||||
free(output->name);
|
free(output->pending.name);
|
||||||
output->name = strdup(name);
|
output->pending.name = strdup(name);
|
||||||
|
output->pending_flags |= WAYLAND_OUTPUT_CHANGED_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zxdg_output_v1_handle_description(void *data,
|
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_output_add_listener(output->wl_output, &output_listener, output);
|
||||||
|
|
||||||
wl_list_init(&output->link);
|
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. */
|
/* Have a fallback while we don't have compositor given name. */
|
||||||
name_len = snprintf(NULL, 0, "WaylandOutput%d", next_output_id);
|
name_len = snprintf(NULL, 0, "WaylandOutput%d", next_output_id);
|
||||||
output->name = malloc(name_len + 1);
|
output->current.name = malloc(name_len + 1);
|
||||||
if (output->name)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -277,8 +334,6 @@ BOOL wayland_output_create(uint32_t id, uint32_t version)
|
||||||
if (process_wayland.zxdg_output_manager_v1)
|
if (process_wayland.zxdg_output_manager_v1)
|
||||||
wayland_output_use_xdg_extension(output);
|
wayland_output_use_xdg_extension(output);
|
||||||
|
|
||||||
wl_list_insert(process_wayland.output_list.prev, &output->link);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -286,9 +341,10 @@ err:
|
||||||
return FALSE;
|
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)
|
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);
|
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)
|
if (output->zxdg_output_v1)
|
||||||
zxdg_output_v1_destroy(output->zxdg_output_v1);
|
zxdg_output_v1_destroy(output->zxdg_output_v1);
|
||||||
wl_output_destroy(output->wl_output);
|
wl_output_destroy(output->wl_output);
|
||||||
free(output->name);
|
|
||||||
free(output);
|
free(output);
|
||||||
|
|
||||||
maybe_init_display_devices();
|
maybe_init_display_devices();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
# error You must include config.h to use this header
|
# error You must include config.h to use this header
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ struct wayland
|
||||||
struct wl_registry *wl_registry;
|
struct wl_registry *wl_registry;
|
||||||
struct zxdg_output_manager_v1 *zxdg_output_manager_v1;
|
struct zxdg_output_manager_v1 *zxdg_output_manager_v1;
|
||||||
struct wl_list output_list;
|
struct wl_list output_list;
|
||||||
|
/* Protects the output_list and the wayland_output.current states. */
|
||||||
|
pthread_mutex_t output_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wayland_output_mode
|
struct wayland_output_mode
|
||||||
|
@ -63,17 +66,24 @@ struct wayland_output_mode
|
||||||
int32_t refresh;
|
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 rb_tree modes;
|
||||||
struct wayland_output_mode *current_mode;
|
struct wayland_output_mode *current_mode;
|
||||||
char *name;
|
char *name;
|
||||||
int logical_x, logical_y;
|
int logical_x, logical_y;
|
||||||
int logical_w, logical_h;
|
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;
|
uint32_t global_id;
|
||||||
|
unsigned int pending_flags;
|
||||||
|
struct wayland_output_state pending;
|
||||||
|
struct wayland_output_state current;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
Loading…
Reference in a new issue