mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-03 00:42:46 +00:00
winewayland.drv: Basic Wayland toplevel surface support.
Use the xdg-shell Wayland protocol to create Wayland xdg_surface xdg_toplevel surfaces for non-child windows.
This commit is contained in:
parent
0066379200
commit
285c47d15d
|
@ -9,6 +9,8 @@ SOURCES = \
|
|||
version.rc \
|
||||
wayland.c \
|
||||
wayland_output.c \
|
||||
wayland_surface.c \
|
||||
waylanddrv_main.c \
|
||||
window.c \
|
||||
xdg-output-unstable-v1.xml
|
||||
xdg-output-unstable-v1.xml \
|
||||
xdg-shell.xml
|
||||
|
|
|
@ -38,6 +38,21 @@ struct wayland process_wayland =
|
|||
.output_mutex = PTHREAD_MUTEX_INITIALIZER
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* xdg_wm_base handling
|
||||
*/
|
||||
|
||||
static void xdg_wm_base_handle_ping(void *data, struct xdg_wm_base *shell,
|
||||
uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(shell, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdg_wm_base_listener =
|
||||
{
|
||||
xdg_wm_base_handle_ping
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* Registry handling
|
||||
*/
|
||||
|
@ -65,6 +80,20 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
|
|||
wl_list_for_each(output, &process_wayland.output_list, link)
|
||||
wayland_output_use_xdg_extension(output);
|
||||
}
|
||||
else if (strcmp(interface, "wl_compositor") == 0)
|
||||
{
|
||||
process_wayland.wl_compositor =
|
||||
wl_registry_bind(registry, id, &wl_compositor_interface, 4);
|
||||
}
|
||||
else if (strcmp(interface, "xdg_wm_base") == 0)
|
||||
{
|
||||
/* Bind version 2 so that compositors (e.g., sway) can properly send tiled
|
||||
* states, instead of falling back to (ab)using the maximized state. */
|
||||
process_wayland.xdg_wm_base =
|
||||
wl_registry_bind(registry, id, &xdg_wm_base_interface,
|
||||
version < 2 ? version : 2);
|
||||
xdg_wm_base_add_listener(process_wayland.xdg_wm_base, &xdg_wm_base_listener, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||
|
@ -136,6 +165,18 @@ BOOL wayland_process_init(void)
|
|||
wl_display_roundtrip_queue(process_wayland.wl_display, process_wayland.wl_event_queue);
|
||||
wl_display_roundtrip_queue(process_wayland.wl_display, process_wayland.wl_event_queue);
|
||||
|
||||
/* Check for required protocol globals. */
|
||||
if (!process_wayland.wl_compositor)
|
||||
{
|
||||
ERR("Wayland compositor doesn't support wl_compositor\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!process_wayland.xdg_wm_base)
|
||||
{
|
||||
ERR("Wayland compositor doesn't support xdg_wm_base\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wayland_init_display_devices(FALSE);
|
||||
|
||||
process_wayland.initialized = TRUE;
|
||||
|
|
179
dlls/winewayland.drv/wayland_surface.c
Normal file
179
dlls/winewayland.drv/wayland_surface.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Wayland surfaces
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "waylanddrv.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
|
||||
|
||||
static void xdg_surface_handle_configure(void *data, struct xdg_surface *xdg_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
struct wayland_surface *surface = data;
|
||||
|
||||
TRACE("serial=%u\n", serial);
|
||||
|
||||
pthread_mutex_lock(&surface->mutex);
|
||||
/* Handle this event only if wayland_surface is still associated with
|
||||
* the target xdg_surface. */
|
||||
if (surface->xdg_surface == xdg_surface)
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
pthread_mutex_unlock(&surface->mutex);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener =
|
||||
{
|
||||
xdg_surface_handle_configure
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_surface_create
|
||||
*
|
||||
* Creates a role-less wayland surface.
|
||||
*/
|
||||
struct wayland_surface *wayland_surface_create(void)
|
||||
{
|
||||
struct wayland_surface *surface;
|
||||
|
||||
surface = calloc(1, sizeof(*surface));
|
||||
if (!surface)
|
||||
{
|
||||
ERR("Failed to allocate space for Wayland surface\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE("surface=%p\n", surface);
|
||||
|
||||
pthread_mutex_init(&surface->mutex, NULL);
|
||||
|
||||
surface->wl_surface = wl_compositor_create_surface(process_wayland.wl_compositor);
|
||||
if (!surface->wl_surface)
|
||||
{
|
||||
ERR("Failed to create wl_surface Wayland surface\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return surface;
|
||||
|
||||
err:
|
||||
if (surface) wayland_surface_destroy(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_surface_destroy
|
||||
*
|
||||
* Destroys a wayland surface.
|
||||
*/
|
||||
void wayland_surface_destroy(struct wayland_surface *surface)
|
||||
{
|
||||
pthread_mutex_lock(&surface->mutex);
|
||||
|
||||
if (surface->xdg_toplevel)
|
||||
{
|
||||
xdg_toplevel_destroy(surface->xdg_toplevel);
|
||||
surface->xdg_toplevel = NULL;
|
||||
}
|
||||
|
||||
if (surface->xdg_surface)
|
||||
{
|
||||
xdg_surface_destroy(surface->xdg_surface);
|
||||
surface->xdg_surface = NULL;
|
||||
}
|
||||
|
||||
if (surface->wl_surface)
|
||||
{
|
||||
wl_surface_destroy(surface->wl_surface);
|
||||
surface->wl_surface = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&surface->mutex);
|
||||
|
||||
wl_display_flush(process_wayland.wl_display);
|
||||
|
||||
pthread_mutex_destroy(&surface->mutex);
|
||||
|
||||
free(surface);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_surface_make_toplevel
|
||||
*
|
||||
* Gives the toplevel role to a plain wayland surface.
|
||||
*/
|
||||
void wayland_surface_make_toplevel(struct wayland_surface *surface)
|
||||
{
|
||||
TRACE("surface=%p\n", surface);
|
||||
|
||||
surface->xdg_surface =
|
||||
xdg_wm_base_get_xdg_surface(process_wayland.xdg_wm_base, surface->wl_surface);
|
||||
if (!surface->xdg_surface) goto err;
|
||||
xdg_surface_add_listener(surface->xdg_surface, &xdg_surface_listener, surface);
|
||||
|
||||
surface->xdg_toplevel = xdg_surface_get_toplevel(surface->xdg_surface);
|
||||
if (!surface->xdg_toplevel) goto err;
|
||||
|
||||
wl_surface_commit(surface->wl_surface);
|
||||
wl_display_flush(process_wayland.wl_display);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
wayland_surface_clear_role(surface);
|
||||
ERR("Failed to assign toplevel role to wayland surface\n");
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* wayland_surface_clear_role
|
||||
*
|
||||
* Clears the role related Wayland objects of a Wayland surface, making it a
|
||||
* plain surface again. We can later assign the same role (but not a
|
||||
* different one!) to the surface.
|
||||
*/
|
||||
void wayland_surface_clear_role(struct wayland_surface *surface)
|
||||
{
|
||||
TRACE("surface=%p\n", surface);
|
||||
|
||||
if (surface->xdg_toplevel)
|
||||
{
|
||||
xdg_toplevel_destroy(surface->xdg_toplevel);
|
||||
surface->xdg_toplevel = NULL;
|
||||
}
|
||||
|
||||
if (surface->xdg_surface)
|
||||
{
|
||||
xdg_surface_destroy(surface->xdg_surface);
|
||||
surface->xdg_surface = NULL;
|
||||
}
|
||||
|
||||
/* Ensure no buffer is attached, otherwise future role assignments may fail. */
|
||||
wl_surface_attach(surface->wl_surface, NULL, 0, 0);
|
||||
wl_surface_commit(surface->wl_surface);
|
||||
|
||||
wl_display_flush(process_wayland.wl_display);
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include <pthread.h>
|
||||
#include <wayland-client.h>
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -58,6 +59,8 @@ struct wayland
|
|||
struct wl_event_queue *wl_event_queue;
|
||||
struct wl_registry *wl_registry;
|
||||
struct zxdg_output_manager_v1 *zxdg_output_manager_v1;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct wl_list output_list;
|
||||
/* Protects the output_list and the wayland_output.current states. */
|
||||
pthread_mutex_t output_mutex;
|
||||
|
@ -91,6 +94,14 @@ struct wayland_output
|
|||
struct wayland_output_state current;
|
||||
};
|
||||
|
||||
struct wayland_surface
|
||||
{
|
||||
struct wl_surface *wl_surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* Wayland initialization
|
||||
*/
|
||||
|
@ -106,6 +117,15 @@ BOOL wayland_output_create(uint32_t id, uint32_t version) DECLSPEC_HIDDEN;
|
|||
void wayland_output_destroy(struct wayland_output *output) DECLSPEC_HIDDEN;
|
||||
void wayland_output_use_xdg_extension(struct wayland_output *output) DECLSPEC_HIDDEN;
|
||||
|
||||
/**********************************************************************
|
||||
* Wayland surface
|
||||
*/
|
||||
|
||||
struct wayland_surface *wayland_surface_create(void) DECLSPEC_HIDDEN;
|
||||
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;
|
||||
|
||||
/**********************************************************************
|
||||
* USER driver functions
|
||||
*/
|
||||
|
@ -115,6 +135,10 @@ void WAYLAND_DestroyWindow(HWND hwnd) DECLSPEC_HIDDEN;
|
|||
BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manager,
|
||||
BOOL force, void *param) DECLSPEC_HIDDEN;
|
||||
LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) DECLSPEC_HIDDEN;
|
||||
void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||
const RECT *window_rect, const RECT *client_rect,
|
||||
const RECT *visible_rect, const RECT *valid_rects,
|
||||
struct window_surface *surface) DECLSPEC_HIDDEN;
|
||||
BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||
const RECT *window_rect, const RECT *client_rect,
|
||||
RECT *visible_rect, struct window_surface **surface) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -35,6 +35,7 @@ static const struct user_driver_funcs waylanddrv_funcs =
|
|||
.pDestroyWindow = WAYLAND_DestroyWindow,
|
||||
.pUpdateDisplayDevices = WAYLAND_UpdateDisplayDevices,
|
||||
.pWindowMessage = WAYLAND_WindowMessage,
|
||||
.pWindowPosChanged = WAYLAND_WindowPosChanged,
|
||||
.pWindowPosChanging = WAYLAND_WindowPosChanging
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ struct wayland_win_data
|
|||
struct rb_entry entry;
|
||||
/* hwnd that this private data belongs to */
|
||||
HWND hwnd;
|
||||
/* wayland surface (if any) for this window */
|
||||
struct wayland_surface *wayland_surface;
|
||||
};
|
||||
|
||||
static int wayland_win_data_cmp_rb(const void *key,
|
||||
|
@ -103,6 +105,7 @@ static void wayland_win_data_destroy(struct wayland_win_data *data)
|
|||
|
||||
pthread_mutex_unlock(&win_data_mutex);
|
||||
|
||||
if (data->wayland_surface) wayland_surface_destroy(data->wayland_surface);
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
@ -136,6 +139,47 @@ static void wayland_win_data_release(struct wayland_win_data *data)
|
|||
pthread_mutex_unlock(&win_data_mutex);
|
||||
}
|
||||
|
||||
static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data)
|
||||
{
|
||||
struct wayland_surface *surface = data->wayland_surface;
|
||||
HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT);
|
||||
BOOL visible, xdg_visible;
|
||||
|
||||
TRACE("hwnd=%p\n", data->hwnd);
|
||||
|
||||
/* We don't want wayland surfaces for child windows. */
|
||||
if (parent != NtUserGetDesktopWindow() && parent != 0)
|
||||
{
|
||||
if (surface) wayland_surface_destroy(surface);
|
||||
surface = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Otherwise ensure that we have a wayland surface. */
|
||||
if (!surface && !(surface = wayland_surface_create())) return;
|
||||
|
||||
visible = (NtUserGetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE) == WS_VISIBLE;
|
||||
xdg_visible = surface->xdg_toplevel != NULL;
|
||||
|
||||
if (visible != xdg_visible)
|
||||
{
|
||||
pthread_mutex_lock(&surface->mutex);
|
||||
|
||||
/* If we have a pre-existing surface ensure it has no role. */
|
||||
if (data->wayland_surface) wayland_surface_clear_role(surface);
|
||||
/* If the window is a visible toplevel make it a wayland
|
||||
* xdg_toplevel. Otherwise keep it role-less to avoid polluting the
|
||||
* compositor with empty xdg_toplevels. */
|
||||
if (visible) wayland_surface_make_toplevel(surface);
|
||||
|
||||
pthread_mutex_unlock(&surface->mutex);
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface);
|
||||
data->wayland_surface = surface;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WAYLAND_DestroyWindow
|
||||
*/
|
||||
|
@ -169,6 +213,27 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* WAYLAND_WindowPosChanged
|
||||
*/
|
||||
void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
|
||||
const RECT *window_rect, const RECT *client_rect,
|
||||
const RECT *visible_rect, const RECT *valid_rects,
|
||||
struct window_surface *surface)
|
||||
{
|
||||
struct wayland_win_data *data = wayland_win_data_get(hwnd);
|
||||
|
||||
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),
|
||||
wine_dbgstr_rect(visible_rect), insert_after, swp_flags);
|
||||
|
||||
if (!data) return;
|
||||
|
||||
wayland_win_data_update_wayland_surface(data);
|
||||
|
||||
wayland_win_data_release(data);
|
||||
}
|
||||
|
||||
static void wayland_resize_desktop(void)
|
||||
{
|
||||
RECT virtual_rect = NtUserGetVirtualScreenRect();
|
||||
|
|
1351
dlls/winewayland.drv/xdg-shell.xml
Normal file
1351
dlls/winewayland.drv/xdg-shell.xml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue