wine/dlls/winewayland.drv/wayland.c
Alexandros Frantzis 4c9c991fae winewayland.drv: Set client area subsurface size.
Use the viewporter Wayland protocol to set the size of the client
area subsurface, so that it always covers the client area bounds
exactly. This may transiently lead to scaled contents.
2023-11-17 10:56:36 +01:00

274 lines
8.8 KiB
C

/*
* Wayland core handling
*
* Copyright (c) 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 "waylanddrv.h"
#include "wine/debug.h"
#include <stdlib.h>
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
struct wayland process_wayland =
{
.seat.mutex = PTHREAD_MUTEX_INITIALIZER,
.keyboard.mutex = PTHREAD_MUTEX_INITIALIZER,
.pointer.mutex = PTHREAD_MUTEX_INITIALIZER,
.output_list = {&process_wayland.output_list, &process_wayland.output_list},
.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
};
/**********************************************************************
* wl_seat handling
*/
static void wl_seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !process_wayland.pointer.wl_pointer)
wayland_pointer_init(wl_seat_get_pointer(seat));
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && process_wayland.pointer.wl_pointer)
wayland_pointer_deinit();
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !process_wayland.keyboard.wl_keyboard)
wayland_keyboard_init(wl_seat_get_keyboard(seat));
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && process_wayland.keyboard.wl_keyboard)
wayland_keyboard_deinit();
}
static void wl_seat_handle_name(void *data, struct wl_seat *seat, const char *name)
{
}
static const struct wl_seat_listener seat_listener =
{
wl_seat_handle_capabilities,
wl_seat_handle_name
};
/**********************************************************************
* Registry handling
*/
static void registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface,
uint32_t version)
{
TRACE("interface=%s version=%u id=%u\n", interface, version, id);
if (strcmp(interface, "wl_output") == 0)
{
if (!wayland_output_create(id, version))
ERR("Failed to create wayland_output for global id=%u\n", id);
}
else if (strcmp(interface, "zxdg_output_manager_v1") == 0)
{
struct wayland_output *output;
process_wayland.zxdg_output_manager_v1 =
wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface,
version < 3 ? version : 3);
/* Add zxdg_output_v1 to existing outputs. */
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);
}
else if (strcmp(interface, "wl_shm") == 0)
{
process_wayland.wl_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
}
else if (strcmp(interface, "wl_seat") == 0)
{
struct wayland_seat *seat = &process_wayland.seat;
if (seat->wl_seat)
{
WARN("Only a single seat is currently supported, ignoring additional seats.\n");
return;
}
pthread_mutex_lock(&seat->mutex);
seat->wl_seat = wl_registry_bind(registry, id, &wl_seat_interface,
version < 5 ? version : 5);
seat->global_id = id;
wl_seat_add_listener(seat->wl_seat, &seat_listener, NULL);
pthread_mutex_unlock(&seat->mutex);
}
else if (strcmp(interface, "wp_viewporter") == 0)
{
process_wayland.wp_viewporter =
wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, "wl_subcompositor") == 0)
{
process_wayland.wl_subcompositor =
wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
}
else if (strcmp(interface, "wp_viewporter") == 0)
{
process_wayland.wp_viewporter =
wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
}
static void registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t id)
{
struct wayland_output *output, *tmp;
struct wayland_seat *seat;
TRACE("id=%u\n", id);
wl_list_for_each_safe(output, tmp, &process_wayland.output_list, link)
{
if (output->global_id == id)
{
TRACE("removing output->name=%s\n", output->current.name);
wayland_output_destroy(output);
return;
}
}
seat = &process_wayland.seat;
if (seat->wl_seat && seat->global_id == id)
{
TRACE("removing seat\n");
if (process_wayland.pointer.wl_pointer) wayland_pointer_deinit();
pthread_mutex_lock(&seat->mutex);
wl_seat_release(seat->wl_seat);
seat->wl_seat = NULL;
seat->global_id = 0;
pthread_mutex_unlock(&seat->mutex);
}
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
/**********************************************************************
* wayland_process_init
*
* Initialise the per process wayland objects.
*
*/
BOOL wayland_process_init(void)
{
struct wl_display *wl_display_wrapper;
process_wayland.wl_display = wl_display_connect(NULL);
if (!process_wayland.wl_display)
return FALSE;
TRACE("wl_display=%p\n", process_wayland.wl_display);
if (!(process_wayland.wl_event_queue = wl_display_create_queue(process_wayland.wl_display)))
{
ERR("Failed to create event queue\n");
return FALSE;
}
if (!(wl_display_wrapper = wl_proxy_create_wrapper(process_wayland.wl_display)))
{
ERR("Failed to create proxy wrapper for wl_display\n");
return FALSE;
}
wl_proxy_set_queue((struct wl_proxy *) wl_display_wrapper,
process_wayland.wl_event_queue);
process_wayland.wl_registry = wl_display_get_registry(wl_display_wrapper);
wl_proxy_wrapper_destroy(wl_display_wrapper);
if (!process_wayland.wl_registry)
{
ERR("Failed to get to wayland registry\n");
return FALSE;
}
/* Populate registry */
wl_registry_add_listener(process_wayland.wl_registry, &registry_listener, NULL);
/* We need two roundtrips. One to get and bind globals, one to handle all
* initial events produced from registering the globals. */
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;
}
if (!process_wayland.wl_shm)
{
ERR("Wayland compositor doesn't support wl_shm\n");
return FALSE;
}
if (!process_wayland.wl_subcompositor)
{
ERR("Wayland compositor doesn't support wl_subcompositor\n");
return FALSE;
}
wayland_init_display_devices(FALSE);
process_wayland.initialized = TRUE;
return TRUE;
}