Wayland mouse support
Fix moving items with mouse when captured on macOS
This commit is contained in:
@@ -85,6 +85,7 @@ target_link_libraries(
|
||||
plat
|
||||
PRIVATE
|
||||
Qt5::Widgets
|
||||
Qt5::Gui
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
@@ -92,10 +93,28 @@ target_link_libraries(
|
||||
ui
|
||||
PRIVATE
|
||||
Qt5::Widgets
|
||||
Qt5::Gui
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(X11 REQUIRED)
|
||||
target_link_libraries(ui PRIVATE X11::X11)
|
||||
find_package(ECM NO_MODULE)
|
||||
if (ECM_FOUND)
|
||||
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||
find_package(Wayland COMPONENTS Client)
|
||||
if (Wayland_FOUND)
|
||||
target_link_libraries(ui PRIVATE Wayland::Client)
|
||||
find_package(WaylandScanner REQUIRED)
|
||||
if (WaylandScanner_FOUND)
|
||||
set(WL_SOURCE_VAR)
|
||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/relative-pointer-unstable-v1.xml BASENAME relative-pointer-unstable-v1)
|
||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
|
||||
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
|
||||
target_compile_definitions(ui PRIVATE WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -38,7 +38,10 @@ bool CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *mess
|
||||
if (eventType == "mac_generic_NSEvent")
|
||||
{
|
||||
NSEvent* event = (NSEvent*)message;
|
||||
if ([event type] == NSEventTypeMouseMoved)
|
||||
if ([event type] == NSEventTypeMouseMoved
|
||||
|| [event type] == NSEventTypeLeftMouseDragged
|
||||
|| [event type] == NSEventTypeRightMouseDragged
|
||||
|| [event type] == NSEventTypeOtherMouseDragged)
|
||||
{
|
||||
mousedata.deltax += [event deltaX];
|
||||
mousedata.deltay += [event deltaY];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <QApplication>
|
||||
#include <QImage>
|
||||
#include <QGuiApplication>
|
||||
#include <qnamespace.h>
|
||||
#include "qt_gleswidget.hpp"
|
||||
#ifdef __APPLE__
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
@@ -43,6 +45,10 @@ void GLESWidget::qt_mouse_poll()
|
||||
mouse_z = mousedata.deltaz;
|
||||
mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0;
|
||||
mouse_buttons = mousedata.mousebuttons;
|
||||
#ifdef WAYLAND
|
||||
if (wayland)
|
||||
wl_mouse_poll();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -75,11 +81,13 @@ void GLESWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture)
|
||||
{
|
||||
plat_mouse_capture(1);
|
||||
this->setCursor(Qt::BlankCursor);
|
||||
return;
|
||||
}
|
||||
if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3)
|
||||
{
|
||||
plat_mouse_capture(0);
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
return;
|
||||
}
|
||||
if (mouse_capture)
|
||||
@@ -93,6 +101,7 @@ void GLESWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
mousedata.mousebuttons |= event->button();
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
void GLESWidget::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
@@ -105,6 +114,11 @@ void GLESWidget::wheelEvent(QWheelEvent *event)
|
||||
int ignoreNextMouseEvent = 0;
|
||||
void GLESWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
{
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
if (!mouse_capture) { event->ignore(); return; }
|
||||
#ifdef __APPLE__
|
||||
event->accept();
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <atomic>
|
||||
#include <qapplication.h>
|
||||
|
||||
#ifdef WAYLAND
|
||||
#include "wl_mouse.hpp"
|
||||
#endif
|
||||
|
||||
class GLESWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
{
|
||||
@@ -15,6 +20,7 @@ class GLESWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
private:
|
||||
QImage m_image{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32};
|
||||
int x, y, w, h, sx, sy, sw, sh;
|
||||
bool wayland = false;
|
||||
public:
|
||||
void resizeGL(int w, int h) override;
|
||||
void initializeGL() override;
|
||||
@@ -23,6 +29,12 @@ public:
|
||||
: QOpenGLWidget(parent), QOpenGLFunctions()
|
||||
{
|
||||
setMinimumSize(16, 16);
|
||||
#ifdef WAYLAND
|
||||
if (QApplication::platformName().contains("wayland")) {
|
||||
wayland = true;
|
||||
wl_init();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
~GLESWidget()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "qt_mainwindow.hpp"
|
||||
#include "ui_qt_mainwindow.h"
|
||||
#include <qguiapplication.h>
|
||||
|
||||
extern "C" {
|
||||
#include <86box/86box.h>
|
||||
@@ -42,7 +43,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
ui->setupUi(this);
|
||||
video_setblit(qt_blit);
|
||||
ui->glesWidget->setMouseTracking(true);
|
||||
//ui->glesWidget->setMouseTracking(true);
|
||||
|
||||
connect(this, &MainWindow::showMessageForNonQtThread, this, &MainWindow::showMessage_, Qt::BlockingQueuedConnection);
|
||||
|
||||
@@ -54,8 +55,21 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(this, &MainWindow::setMouseCapture, this, [this](bool state) {
|
||||
mouse_capture = state ? 1 : 0;
|
||||
qt_mouse_capture(mouse_capture);
|
||||
if (mouse_capture) ui->glesWidget->grabMouse();
|
||||
else ui->glesWidget->releaseMouse();
|
||||
if (mouse_capture) {
|
||||
ui->glesWidget->grabMouse();
|
||||
#ifdef WAYLAND
|
||||
if (QGuiApplication::platformName().contains("wayland")) {
|
||||
wl_mouse_capture(this->windowHandle());
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
ui->glesWidget->releaseMouse();
|
||||
#ifdef WAYLAND
|
||||
if (QGuiApplication::platformName().contains("wayland")) {
|
||||
wl_mouse_uncapture();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
connect(this, &MainWindow::resizeContents, this, [this](int w, int h) {
|
||||
|
||||
89
src/qt/wl_mouse.cpp
Normal file
89
src/qt/wl_mouse.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "wl_mouse.hpp"
|
||||
#include <QGuiApplication>
|
||||
#include <wayland-client-core.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-relative-pointer-unstable-v1-client-protocol.h>
|
||||
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <QWindow>
|
||||
#include <QGuiApplication>
|
||||
|
||||
static zwp_relative_pointer_manager_v1* rel_manager = nullptr;
|
||||
static zwp_relative_pointer_v1* rel_pointer = nullptr;
|
||||
static zwp_pointer_constraints_v1* conf_pointer_interface = nullptr;
|
||||
static zwp_locked_pointer_v1* conf_pointer = nullptr;
|
||||
|
||||
static int rel_mouse_x = 0, rel_mouse_y = 0;
|
||||
|
||||
void rel_mouse_event(void* data, zwp_relative_pointer_v1* zwp_relative_pointer_v1, uint32_t tstmp, uint32_t tstmpl, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_real, wl_fixed_t dy_real)
|
||||
{
|
||||
rel_mouse_x += wl_fixed_to_int(dx_real);
|
||||
rel_mouse_y += wl_fixed_to_int(dy_real);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern int mouse_x, mouse_y;
|
||||
}
|
||||
|
||||
void wl_mouse_poll()
|
||||
{
|
||||
mouse_x = rel_mouse_x;
|
||||
mouse_y = rel_mouse_y;
|
||||
rel_mouse_x = 0;
|
||||
rel_mouse_y = 0;
|
||||
}
|
||||
|
||||
static struct zwp_relative_pointer_v1_listener rel_listener =
|
||||
{
|
||||
rel_mouse_event
|
||||
};
|
||||
|
||||
static void
|
||||
display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
||||
const char *interface, uint32_t version)
|
||||
{
|
||||
if (!strcmp(interface, "zwp_relative_pointer_manager_v1"))
|
||||
{
|
||||
rel_manager = (zwp_relative_pointer_manager_v1*)wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, version);
|
||||
}
|
||||
if (!strcmp(interface, "zwp_pointer_constraints_v1"))
|
||||
{
|
||||
conf_pointer_interface = (zwp_pointer_constraints_v1*)wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, version);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
display_handle_global,
|
||||
nullptr
|
||||
};
|
||||
|
||||
void wl_init()
|
||||
{
|
||||
wl_display* display = (wl_display*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display");
|
||||
if (display)
|
||||
{
|
||||
auto registry = wl_display_get_registry(display);
|
||||
if (registry)
|
||||
{
|
||||
wl_registry_add_listener(registry, ®istry_listener, nullptr);
|
||||
wl_display_roundtrip(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wl_mouse_capture(QWindow *window)
|
||||
{
|
||||
rel_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(rel_manager, (wl_pointer*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer"));
|
||||
zwp_relative_pointer_v1_add_listener(rel_pointer, &rel_listener, nullptr);
|
||||
conf_pointer = zwp_pointer_constraints_v1_lock_pointer(conf_pointer_interface, (wl_surface*)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_pointer*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer"), nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
}
|
||||
|
||||
void wl_mouse_uncapture()
|
||||
{
|
||||
zwp_locked_pointer_v1_destroy(conf_pointer);
|
||||
zwp_relative_pointer_v1_destroy(rel_pointer);
|
||||
rel_pointer = nullptr;
|
||||
conf_pointer = nullptr;
|
||||
}
|
||||
5
src/qt/wl_mouse.hpp
Normal file
5
src/qt/wl_mouse.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
class QWindow;
|
||||
void wl_mouse_capture(QWindow* window);
|
||||
void wl_mouse_uncapture();
|
||||
void wl_mouse_poll();
|
||||
void wl_init();
|
||||
Reference in New Issue
Block a user