From d53cb7206d65db3f70a5f2390e53cc2e9c408c62 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Fri, 5 May 2023 11:20:10 +0300 Subject: [PATCH] winewayland.drv: Introduce window_surface for Wayland. --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/waylanddrv.h | 6 + dlls/winewayland.drv/window.c | 39 +++++- dlls/winewayland.drv/window_surface.c | 184 ++++++++++++++++++++++++++ 4 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 dlls/winewayland.drv/window_surface.c diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 9a682e7e007..ef75c289b76 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -12,5 +12,6 @@ SOURCES = \ wayland_surface.c \ waylanddrv_main.c \ window.c \ + window_surface.c \ xdg-output-unstable-v1.xml \ xdg-shell.xml diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 1fa45b041e7..6094fb680cb 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -126,6 +126,12 @@ void wayland_surface_destroy(struct wayland_surface *surface) DECLSPEC_HIDDEN; void wayland_surface_make_toplevel(struct wayland_surface *surface) DECLSPEC_HIDDEN; void wayland_surface_clear_role(struct wayland_surface *surface) DECLSPEC_HIDDEN; +/********************************************************************** + * Wayland window surface + */ + +struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect) DECLSPEC_HIDDEN; + /********************************************************************** * USER driver functions */ diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 8e73b82899e..e43552a44a8 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -41,6 +41,8 @@ struct wayland_win_data HWND hwnd; /* wayland surface (if any) for this window */ struct wayland_surface *wayland_surface; + /* wine window_surface backing this window */ + struct window_surface *window_surface; }; static int wayland_win_data_cmp_rb(const void *key, @@ -105,6 +107,7 @@ static void wayland_win_data_destroy(struct wayland_win_data *data) pthread_mutex_unlock(&win_data_mutex); + if (data->window_surface) window_surface_release(data->window_surface); if (data->wayland_surface) wayland_surface_destroy(data->wayland_surface); free(data); } @@ -201,6 +204,9 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, RECT *visible_rect, struct window_surface **surface) { struct wayland_win_data *data = wayland_win_data_get(hwnd); + HWND parent; + BOOL visible; + RECT surface_rect; TRACE("hwnd %p window %s client %s visible %s after %p flags %08x\n", hwnd, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect), @@ -208,8 +214,35 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags, if (!data && !(data = wayland_win_data_create(hwnd))) return TRUE; - wayland_win_data_release(data); + /* Release the dummy surface wine provides for toplevels. */ + if (*surface) window_surface_release(*surface); + *surface = NULL; + parent = NtUserGetAncestor(hwnd, GA_PARENT); + visible = ((NtUserGetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) || + (swp_flags & SWP_SHOWWINDOW)) && + !(swp_flags & SWP_HIDEWINDOW); + + /* Check if we don't want a dedicated window surface. */ + if ((parent && parent != NtUserGetDesktopWindow()) || !visible) goto done; + + surface_rect = *window_rect; + OffsetRect(&surface_rect, -surface_rect.left, -surface_rect.top); + + /* Check if we can reuse our current window surface. */ + if (data->window_surface && + EqualRect(&data->window_surface->rect, &surface_rect)) + { + window_surface_add_ref(data->window_surface); + *surface = data->window_surface; + TRACE("reusing surface %p\n", *surface); + goto done; + } + + *surface = wayland_window_surface_create(data->hwnd, &surface_rect); + +done: + wayland_win_data_release(data); return TRUE; } @@ -229,6 +262,10 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, if (!data) return; + if (surface) window_surface_add_ref(surface); + if (data->window_surface) window_surface_release(data->window_surface); + data->window_surface = surface; + wayland_win_data_update_wayland_surface(data); wayland_win_data_release(data); diff --git a/dlls/winewayland.drv/window_surface.c b/dlls/winewayland.drv/window_surface.c new file mode 100644 index 00000000000..9f6f00058e7 --- /dev/null +++ b/dlls/winewayland.drv/window_surface.c @@ -0,0 +1,184 @@ +/* + * Wayland window surface implementation + * + * Copyright 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include + +#include "waylanddrv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + +struct wayland_window_surface +{ + struct window_surface header; + HWND hwnd; + RECT bounds; + void *bits; + pthread_mutex_t mutex; + BITMAPINFO info; +}; + +static struct wayland_window_surface *wayland_window_surface_cast( + struct window_surface *window_surface) +{ + return (struct wayland_window_surface *)window_surface; +} + +static inline void reset_bounds(RECT *bounds) +{ + bounds->left = bounds->top = INT_MAX; + bounds->right = bounds->bottom = INT_MIN; +} + +/*********************************************************************** + * wayland_window_surface_lock + */ +static void wayland_window_surface_lock(struct window_surface *window_surface) +{ + struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface); + pthread_mutex_lock(&wws->mutex); +} + +/*********************************************************************** + * wayland_window_surface_unlock + */ +static void wayland_window_surface_unlock(struct window_surface *window_surface) +{ + struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface); + pthread_mutex_unlock(&wws->mutex); +} + +/*********************************************************************** + * wayland_window_surface_get_bitmap_info + */ +static void *wayland_window_surface_get_bitmap_info(struct window_surface *window_surface, + BITMAPINFO *info) +{ + struct wayland_window_surface *surface = wayland_window_surface_cast(window_surface); + /* We don't store any additional information at the end of our BITMAPINFO, so + * just copy the structure itself. */ + memcpy(info, &surface->info, sizeof(*info)); + return surface->bits; +} + +/*********************************************************************** + * wayland_window_surface_get_bounds + */ +static RECT *wayland_window_surface_get_bounds(struct window_surface *window_surface) +{ + struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface); + return &wws->bounds; +} + +/*********************************************************************** + * wayland_window_surface_set_region + */ +static void wayland_window_surface_set_region(struct window_surface *window_surface, + HRGN region) +{ + /* TODO */ +} + +/*********************************************************************** + * wayland_window_surface_flush + */ +static void wayland_window_surface_flush(struct window_surface *window_surface) +{ + /* TODO */ +} + +/*********************************************************************** + * wayland_window_surface_destroy + */ +static void wayland_window_surface_destroy(struct window_surface *window_surface) +{ + struct wayland_window_surface *wws = wayland_window_surface_cast(window_surface); + + TRACE("surface=%p\n", wws); + + pthread_mutex_destroy(&wws->mutex); + free(wws->bits); + free(wws); +} + +static const struct window_surface_funcs wayland_window_surface_funcs = +{ + wayland_window_surface_lock, + wayland_window_surface_unlock, + wayland_window_surface_get_bitmap_info, + wayland_window_surface_get_bounds, + wayland_window_surface_set_region, + wayland_window_surface_flush, + wayland_window_surface_destroy +}; + +/*********************************************************************** + * wayland_window_surface_create + */ +struct window_surface *wayland_window_surface_create(HWND hwnd, const RECT *rect) +{ + struct wayland_window_surface *wws; + int width = rect->right - rect->left; + int height = rect->bottom - rect->top; + pthread_mutexattr_t mutexattr; + + TRACE("hwnd %p rect %s\n", hwnd, wine_dbgstr_rect(rect)); + + wws = calloc(1, sizeof(*wws)); + if (!wws) return NULL; + wws->info.bmiHeader.biSize = sizeof(wws->info.bmiHeader); + wws->info.bmiHeader.biClrUsed = 0; + wws->info.bmiHeader.biBitCount = 32; + wws->info.bmiHeader.biCompression = BI_RGB; + wws->info.bmiHeader.biWidth = width; + wws->info.bmiHeader.biHeight = -height; /* top-down */ + wws->info.bmiHeader.biPlanes = 1; + wws->info.bmiHeader.biSizeImage = width * height * 4; + + pthread_mutexattr_init(&mutexattr); + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&wws->mutex, &mutexattr); + pthread_mutexattr_destroy(&mutexattr); + + wws->header.funcs = &wayland_window_surface_funcs; + wws->header.rect = *rect; + wws->header.ref = 1; + wws->hwnd = hwnd; + reset_bounds(&wws->bounds); + + if (!(wws->bits = malloc(wws->info.bmiHeader.biSizeImage))) + goto failed; + + TRACE("created %p hwnd %p %s bits [%p,%p)\n", wws, hwnd, wine_dbgstr_rect(rect), + wws->bits, (char *)wws->bits + wws->info.bmiHeader.biSizeImage); + + return &wws->header; + +failed: + wayland_window_surface_destroy(&wws->header); + return NULL; +}