diff --git a/QtScrcpy/device/ui/videoform.cpp b/QtScrcpy/device/ui/videoform.cpp index d555ac2..5520260 100644 --- a/QtScrcpy/device/ui/videoform.cpp +++ b/QtScrcpy/device/ui/videoform.cpp @@ -92,6 +92,7 @@ QRect VideoForm::getGrabCursorRect() // high dpi support rc.setTopLeft(rc.topLeft() * m_videoWidget->devicePixelRatio()); rc.setBottomRight(rc.bottomRight() * m_videoWidget->devicePixelRatio()); + rc.setX(rc.x() + 10); rc.setY(rc.y() + 10); rc.setWidth(rc.width() - 20); @@ -100,12 +101,21 @@ QRect VideoForm::getGrabCursorRect() rc = m_videoWidget->geometry(); rc.setTopLeft(ui->keepRadioWidget->mapToGlobal(rc.topLeft())); rc.setBottomRight(ui->keepRadioWidget->mapToGlobal(rc.bottomRight())); + + rc.setX(rc.x() + 10); + rc.setY(rc.y() + 10); + rc.setWidth(rc.width() - 20); + rc.setHeight(rc.height() - 20); +#elif defined(Q_OS_LINUX) + rc = QRect(ui->keepRadioWidget->mapToGlobal(m_videoWidget->pos()), m_videoWidget->size()); + // high dpi support -- taken from the WIN32 section and untested + rc.setTopLeft(rc.topLeft() * m_videoWidget->devicePixelRatio()); + rc.setBottomRight(rc.bottomRight() * m_videoWidget->devicePixelRatio()); + rc.setX(rc.x() + 10); rc.setY(rc.y() + 10); rc.setWidth(rc.width() - 20); rc.setHeight(rc.height() - 20); -#else - #endif return rc; } diff --git a/QtScrcpy/util/mousetap/mousetap.cpp b/QtScrcpy/util/mousetap/mousetap.cpp index da1bc13..4363dda 100644 --- a/QtScrcpy/util/mousetap/mousetap.cpp +++ b/QtScrcpy/util/mousetap/mousetap.cpp @@ -7,6 +7,9 @@ #ifdef Q_OS_OSX #include "cocoamousetap.h" #endif +#ifdef Q_OS_LINUX +#include "xmousetap.h" +#endif MouseTap *MouseTap::s_instance = Q_NULLPTR; MouseTap *MouseTap::getInstance() @@ -19,7 +22,7 @@ MouseTap *MouseTap::getInstance() s_instance = new CocoaMouseTap(); #endif #ifdef Q_OS_LINUX - Q_ASSERT(false); + s_instance = new XMouseTap(); #endif } return s_instance; diff --git a/QtScrcpy/util/mousetap/mousetap.pri b/QtScrcpy/util/mousetap/mousetap.pri index e2d7d09..4bc8b4e 100644 --- a/QtScrcpy/util/mousetap/mousetap.pri +++ b/QtScrcpy/util/mousetap/mousetap.pri @@ -16,3 +16,10 @@ mac { LIBS += -framework Appkit QMAKE_CFLAGS += -mmacosx-version-min=10.6 } + +linux { + HEADERS += $$PWD/xmousetap.h + SOURCES += $$PWD/xmousetap.cpp + LIBS += -lxcb + QT += x11extras +} diff --git a/QtScrcpy/util/mousetap/xmousetap.cpp b/QtScrcpy/util/mousetap/xmousetap.cpp new file mode 100644 index 0000000..18ba226 --- /dev/null +++ b/QtScrcpy/util/mousetap/xmousetap.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include +#include + +#include "xmousetap.h" + +XMouseTap::XMouseTap() {} + +XMouseTap::~XMouseTap() {} + +void XMouseTap::initMouseEventTap() {} + +void XMouseTap::quitMouseEventTap() {} + +static void find_grab_window_recursive(xcb_connection_t *dpy, xcb_window_t window, + QRect rc, int16_t offset_x, int16_t offset_y, + xcb_window_t *grab_window, uint32_t *grab_window_size) { + xcb_query_tree_cookie_t tree_cookie; + xcb_query_tree_reply_t *tree; + tree_cookie = xcb_query_tree(dpy, window); + tree = xcb_query_tree_reply(dpy, tree_cookie, NULL); + + xcb_window_t *children = xcb_query_tree_children(tree); + for (int i = 0; i < xcb_query_tree_children_length(tree); i++) { + xcb_get_geometry_cookie_t gg_cookie; + xcb_get_geometry_reply_t *gg; + gg_cookie = xcb_get_geometry(dpy, children[i]); + gg = xcb_get_geometry_reply(dpy, gg_cookie, NULL); + + if (gg->x + offset_x <= rc.left() && gg->x + offset_x + gg->width >= rc.right() && + gg->y + offset_y <= rc.top() && gg->y + offset_y + gg->height >= rc.bottom()) { + if (!*grab_window || gg->width * gg->height <= *grab_window_size) { + *grab_window = children[i]; + *grab_window_size = gg->width * gg->height; + } + } + + find_grab_window_recursive(dpy, children[i], rc, + gg->x + offset_x, gg->y + offset_y, + grab_window, grab_window_size); + + free(gg); + } + + free(tree); +} + +void XMouseTap::enableMouseEventTap(QRect rc, bool enabled) { + if (enabled && rc.isEmpty()) { + return; + } + + xcb_connection_t *dpy = QX11Info::connection(); + + if (enabled) { + // We grab the top-most smallest window + xcb_window_t grab_window = 0; + uint32_t grab_window_size = 0; + + find_grab_window_recursive(dpy, QX11Info::appRootWindow(QX11Info::appScreen()), + rc, 0, 0, &grab_window, &grab_window_size); + + if (grab_window) { + xcb_grab_pointer_cookie_t grab_cookie; + xcb_grab_pointer_reply_t *grab; + grab_cookie = xcb_grab_pointer(dpy, /* owner_events = */ 1, + grab_window, /* event_mask = */ 0, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, + grab_window, XCB_NONE, XCB_CURRENT_TIME); + grab = xcb_grab_pointer_reply(dpy, grab_cookie, NULL); + + free(grab); + } + } else { + xcb_void_cookie_t ungrab_cookie; + xcb_generic_error_t *error; + ungrab_cookie = xcb_ungrab_pointer_checked(dpy, XCB_CURRENT_TIME); + error = xcb_request_check(dpy, ungrab_cookie); + + free(error); + } +} diff --git a/QtScrcpy/util/mousetap/xmousetap.h b/QtScrcpy/util/mousetap/xmousetap.h new file mode 100644 index 0000000..83756ab --- /dev/null +++ b/QtScrcpy/util/mousetap/xmousetap.h @@ -0,0 +1,17 @@ +#ifndef XMOUSETAP_H +#define XMOUSETAP_H + +#include "mousetap.h" + +class XMouseTap : public MouseTap +{ +public: + XMouseTap(); + virtual ~XMouseTap(); + + void initMouseEventTap() override; + void quitMouseEventTap() override; + void enableMouseEventTap(QRect rc, bool enabled) override; +}; + +#endif // XMOUSETAP_H