mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-12-24 18:20:05 +00:00
bootmanager: Add wayland protocols
* zwp_relative_pointer_v1 + zwp_locked_pointer_v1 for mouse panning * wp_viewporter for compositor side scaling
This commit is contained in:
parent
9e27dbb53b
commit
395be2269b
@ -60,6 +60,9 @@ public:
|
||||
// Connection to a display server. This is used on X11 and Wayland platforms.
|
||||
void* display_connection = nullptr;
|
||||
|
||||
// Mouse pointer. This is used on Wayland platforms.
|
||||
void* mouse_pointer = nullptr;
|
||||
|
||||
// Render surface. This is a pointer to the native window handle, which depends
|
||||
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
|
||||
// set to nullptr, the video backend will run in headless mode.
|
||||
|
@ -393,6 +393,33 @@ if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(ECM NO_MODULE)
|
||||
if (ECM_FOUND)
|
||||
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||
find_package(Wayland COMPONENTS Client)
|
||||
if (Wayland_FOUND)
|
||||
find_package(WaylandScanner REQUIRED)
|
||||
find_package(WaylandProtocols 1.15 REQUIRED)
|
||||
ecm_add_wayland_client_protocol(WAYLAND_PROTOCOL_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml
|
||||
BASENAME relative-pointer-unstable-v1)
|
||||
ecm_add_wayland_client_protocol(WAYLAND_PROTOCOL_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
|
||||
BASENAME pointer-constraints-unstable-v1)
|
||||
ecm_add_wayland_client_protocol(WAYLAND_PROTOCOL_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml
|
||||
BASENAME viewporter)
|
||||
|
||||
target_link_libraries(yuzu PRIVATE Wayland::Client)
|
||||
target_sources(yuzu PRIVATE ${WAYLAND_PROTOCOL_SRCS})
|
||||
set_source_files_properties(${WAYLAND_PROTOCOL_SRCS} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
|
||||
|
||||
target_compile_definitions(yuzu PRIVATE HAS_WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(yuzu PRIVATE
|
||||
# Use QStringBuilder for string concatenation to reduce
|
||||
# the overall number of temporary strings created.
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include <QWindow>
|
||||
#include <QtCore/qobjectdefs.h>
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <wayland-client.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAS_OPENGL
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
@ -354,6 +359,17 @@ void GRenderWindow::OnFramebufferSizeChanged() {
|
||||
const qreal pixel_ratio = windowPixelRatio();
|
||||
const u32 width = this->width() * pixel_ratio;
|
||||
const u32 height = this->height() * pixel_ratio;
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
if (viewport) {
|
||||
if (width > 0 && height > 0) {
|
||||
wp_viewport_set_destination(viewport, this->width(), this->height());
|
||||
} else {
|
||||
wp_viewport_set_destination(viewport, -1, -1);
|
||||
}
|
||||
}
|
||||
#endif // HAS_WAYLAND
|
||||
|
||||
UpdateCurrentFramebufferLayout(width, height);
|
||||
}
|
||||
|
||||
@ -661,7 +677,99 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
||||
emit MouseActivity();
|
||||
}
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
void GRenderWindow::GlobalAddHandler(void* data, wl_registry* registry, u32 name,
|
||||
const char* interface, u32 version) {
|
||||
GRenderWindow* render_window = static_cast<GRenderWindow*>(data);
|
||||
|
||||
if (std::strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0 &&
|
||||
version == static_cast<u32>(zwp_pointer_constraints_v1_interface.version)) {
|
||||
render_window->pointer_constraints = static_cast<zwp_pointer_constraints_v1*>(
|
||||
wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, version));
|
||||
} else if (std::strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0 &&
|
||||
version == static_cast<u32>(zwp_relative_pointer_manager_v1_interface.version)) {
|
||||
render_window->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1*>(
|
||||
wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, version));
|
||||
} else if (std::strcmp(interface, wp_viewporter_interface.name) == 0) {
|
||||
render_window->viewporter = static_cast<wp_viewporter*>(
|
||||
wl_registry_bind(registry, name, &wp_viewporter_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
void GRenderWindow::GlobalRemoveHandler(void* data, wl_registry* registry, u32 name) {}
|
||||
|
||||
void GRenderWindow::RelativePointerMotionHandler(void* data,
|
||||
zwp_relative_pointer_v1* zwp_relative_pointer_v1,
|
||||
u32 utime_hi, u32 utime_lo, wl_fixed_t dx,
|
||||
wl_fixed_t dy, wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel) {
|
||||
GRenderWindow* render_window = static_cast<GRenderWindow*>(data);
|
||||
render_window->CheckWaylandPointerLock();
|
||||
if (!render_window->IsWaylandPointerLocked())
|
||||
return;
|
||||
|
||||
render_window->input_subsystem->GetMouse()->Move(wl_fixed_to_int(dx_unaccel),
|
||||
wl_fixed_to_int(dy_unaccel), 0, 0);
|
||||
}
|
||||
|
||||
void GRenderWindow::PointerLockedHandler(void* data, zwp_locked_pointer_v1*) {
|
||||
GRenderWindow* render_window = static_cast<GRenderWindow*>(data);
|
||||
render_window->setCursor(QCursor(Qt::BlankCursor));
|
||||
}
|
||||
void GRenderWindow::PointerUnlockedHandler(void* data, zwp_locked_pointer_v1*) {
|
||||
GRenderWindow* render_window = static_cast<GRenderWindow*>(data);
|
||||
render_window->locked_pointer = nullptr;
|
||||
render_window->unsetCursor();
|
||||
}
|
||||
|
||||
void GRenderWindow::CheckWaylandPointerLock() {
|
||||
if (!pointer_constraints || !relative_pointer_manager)
|
||||
return;
|
||||
|
||||
bool mouse_panning = Settings::values.mouse_panning && !Settings::values.mouse_enabled;
|
||||
|
||||
if (IsWaylandPointerLocked() != mouse_panning) {
|
||||
if (mouse_panning) {
|
||||
LockWaylandPointer();
|
||||
} else {
|
||||
UnlockWaylandPointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GRenderWindow::IsWaylandPointerLocked() {
|
||||
return locked_pointer;
|
||||
}
|
||||
|
||||
void GRenderWindow::LockWaylandPointer() {
|
||||
if (pointer_constraints && relative_pointer && !locked_pointer) {
|
||||
locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
|
||||
pointer_constraints, static_cast<wl_surface*>(window_info.render_surface),
|
||||
static_cast<wl_pointer*>(window_info.mouse_pointer), nullptr,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT);
|
||||
|
||||
static constexpr zwp_locked_pointer_v1_listener locked_pointer_listener = {
|
||||
.locked = PointerLockedHandler,
|
||||
.unlocked = PointerUnlockedHandler,
|
||||
};
|
||||
zwp_locked_pointer_v1_add_listener(locked_pointer, &locked_pointer_listener, this);
|
||||
}
|
||||
}
|
||||
|
||||
void GRenderWindow::UnlockWaylandPointer() {
|
||||
if (locked_pointer) {
|
||||
zwp_locked_pointer_v1_destroy(locked_pointer);
|
||||
locked_pointer = nullptr;
|
||||
}
|
||||
}
|
||||
#endif // HAS_WAYLAND
|
||||
|
||||
void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
|
||||
#ifdef HAS_WAYLAND
|
||||
if (IsWaylandPointerLocked())
|
||||
return;
|
||||
#endif // HAS_WAYLAND
|
||||
|
||||
// Touch input is handled in TouchUpdateEvent
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||
return;
|
||||
@ -941,6 +1049,39 @@ bool GRenderWindow::InitRenderTarget() {
|
||||
// Update the Window System information with the new render target
|
||||
window_info = QtCommon::GetWindowSystemInfo(child_widget->windowHandle());
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
|
||||
wl_display* display = static_cast<wl_display*>(window_info.display_connection);
|
||||
|
||||
wl_registry* registry = wl_display_get_registry(display);
|
||||
|
||||
static constexpr wl_registry_listener registryListener = {
|
||||
.global = GlobalAddHandler,
|
||||
.global_remove = GlobalRemoveHandler,
|
||||
};
|
||||
wl_registry_add_listener(registry, ®istryListener, this);
|
||||
|
||||
// This should run GlobalAddHandler getting the protocol globals
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
if (viewporter) {
|
||||
viewport = wp_viewporter_get_viewport(
|
||||
viewporter, static_cast<wl_surface*>(window_info.render_surface));
|
||||
}
|
||||
|
||||
if (relative_pointer_manager) {
|
||||
relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
relative_pointer_manager, static_cast<wl_pointer*>(window_info.mouse_pointer));
|
||||
|
||||
static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
||||
.relative_motion = RelativePointerMotionHandler,
|
||||
};
|
||||
zwp_relative_pointer_v1_add_listener(relative_pointer, &relative_pointer_listener,
|
||||
this);
|
||||
}
|
||||
}
|
||||
#endif // HAS_WAYLAND
|
||||
|
||||
child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height);
|
||||
layout()->addWidget(child_widget);
|
||||
// Reset minimum required size to avoid resizing issues on the main window after restarting.
|
||||
|
@ -23,6 +23,12 @@
|
||||
#include <qnamespace.h>
|
||||
#include <qobjectdefs.h>
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||
#include <wayland-relative-pointer-unstable-v1-client-protocol.h>
|
||||
#include <wayland-viewporter-client-protocol.h>
|
||||
#endif
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
@ -227,6 +233,32 @@ signals:
|
||||
void TasPlaybackStateChanged();
|
||||
|
||||
private:
|
||||
#ifdef HAS_WAYLAND
|
||||
static void GlobalAddHandler(void* data, wl_registry* registry, u32 name, const char* interface,
|
||||
u32 version);
|
||||
static void GlobalRemoveHandler(void* data, wl_registry* registry, u32 name);
|
||||
static void RelativePointerMotionHandler(void* data,
|
||||
zwp_relative_pointer_v1* zwp_relative_pointer_v1,
|
||||
u32 utime_hi, u32 utime_lo, wl_fixed_t dx,
|
||||
wl_fixed_t dy, wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel);
|
||||
static void PointerLockedHandler(void* data, zwp_locked_pointer_v1* zwp_relative_pointer_v1);
|
||||
static void PointerUnlockedHandler(void* data, zwp_locked_pointer_v1* zwp_relative_pointer_v1);
|
||||
|
||||
void CheckWaylandPointerLock();
|
||||
bool IsWaylandPointerLocked();
|
||||
void LockWaylandPointer();
|
||||
void UnlockWaylandPointer();
|
||||
|
||||
zwp_pointer_constraints_v1* pointer_constraints = nullptr;
|
||||
zwp_relative_pointer_manager_v1* relative_pointer_manager = nullptr;
|
||||
wp_viewporter* viewporter = nullptr;
|
||||
|
||||
zwp_relative_pointer_v1* relative_pointer = nullptr;
|
||||
zwp_locked_pointer_v1* locked_pointer = nullptr;
|
||||
wp_viewport* viewport = nullptr;
|
||||
#endif
|
||||
|
||||
void TouchBeginEvent(const QTouchEvent* event);
|
||||
void TouchUpdateEvent(const QTouchEvent* event);
|
||||
void TouchEndEvent();
|
||||
|
@ -48,6 +48,7 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
wsi.mouse_pointer = pni->nativeResourceForIntegration("wl_pointer");
|
||||
if (wsi.type == Core::Frontend::WindowSystemType::Wayland)
|
||||
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user