diff --git a/plugins/platforms/x11/standalone/windowselector.h b/plugins/platforms/x11/standalone/windowselector.h --- a/plugins/platforms/x11/standalone/windowselector.h +++ b/plugins/platforms/x11/standalone/windowselector.h @@ -29,6 +29,8 @@ #include +class QPoint; + namespace KWin { class Toplevel; @@ -41,6 +43,7 @@ ~WindowSelector(); void start(std::function callback, const QByteArray &cursorName); + void start(std::function callback); bool isActive() const { return m_active; } @@ -55,8 +58,11 @@ void handleKeyPress(xcb_keycode_t keycode, uint16_t state); void handleButtonRelease(xcb_button_t button, xcb_window_t window); void selectWindowId(xcb_window_t window_to_kill); + bool activate(const QByteArray &cursorName = QByteArray()); + void cancelCallback(); bool m_active; std::function m_callback; + std::function m_pointSelectionFallback; }; } // namespace diff --git a/plugins/platforms/x11/standalone/windowselector.cpp b/plugins/platforms/x11/standalone/windowselector.cpp --- a/plugins/platforms/x11/standalone/windowselector.cpp +++ b/plugins/platforms/x11/standalone/windowselector.cpp @@ -56,31 +56,55 @@ void WindowSelector::start(std::function callback, const QByteArray &cursorName) { - xcb_cursor_t cursor = createCursor(cursorName); if (m_active) { callback(nullptr); return; } + m_active = activate(cursorName); + if (!m_active) { + callback(nullptr); + return; + } + m_callback = callback; +} + +void WindowSelector::start(std::function callback) +{ + if (m_active) { + callback(QPoint(-1, -1)); + return; + } + + m_active = activate(); + if (!m_active) { + callback(QPoint(-1, -1)); + return; + } + m_pointSelectionFallback = callback; +} + +bool WindowSelector::activate(const QByteArray &cursorName) +{ + xcb_cursor_t cursor = createCursor(cursorName); + xcb_connection_t *c = connection(); ScopedCPointer grabPointer(xcb_grab_pointer_reply(c, xcb_grab_pointer_unchecked(c, false, rootWindow(), XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor, XCB_TIME_CURRENT_TIME), NULL)); if (grabPointer.isNull() || grabPointer->status != XCB_GRAB_STATUS_SUCCESS) { - callback(nullptr); - return; + return false; } - m_active = grabXKeyboard(); - if (!m_active) { + const bool grabbed = grabXKeyboard(); + if (grabbed) { + grabXServer(); + } else { xcb_ungrab_pointer(connection(), XCB_TIME_CURRENT_TIME); - callback(nullptr); - return; } - grabXServer(); - m_callback = callback; + return grabbed; } xcb_cursor_t WindowSelector::createCursor(const QByteArray &cursorName) @@ -136,12 +160,16 @@ void WindowSelector::handleButtonRelease(xcb_button_t button, xcb_window_t window) { if (button == XCB_BUTTON_INDEX_3) { - m_callback(nullptr); + cancelCallback(); release(); return; } if (button == XCB_BUTTON_INDEX_1 || button == XCB_BUTTON_INDEX_2) { - selectWindowId(window); + if (m_callback) { + selectWindowId(window); + } else if (m_pointSelectionFallback) { + m_pointSelectionFallback(Cursor::pos()); + } release(); return; } @@ -173,11 +201,15 @@ } Cursor::setPos(Cursor::pos() + QPoint(mx, my)); if (returnPressed) { - selectWindowUnderPointer(); + if (m_callback) { + selectWindowUnderPointer(); + } else if (m_pointSelectionFallback) { + m_pointSelectionFallback(Cursor::pos()); + } } if (returnPressed || escapePressed) { if (escapePressed) { - m_callback(nullptr); + cancelCallback(); } release(); } @@ -199,6 +231,7 @@ ungrabXServer(); m_active = false; m_callback = std::function(); + m_pointSelectionFallback = std::function(); } void WindowSelector::selectWindowId(xcb_window_t window_to_select) @@ -228,4 +261,13 @@ } } +void WindowSelector::cancelCallback() +{ + if (m_callback) { + m_callback(nullptr); + } else if (m_pointSelectionFallback) { + m_pointSelectionFallback(QPoint(-1, -1)); + } +} + } // namespace diff --git a/plugins/platforms/x11/standalone/x11_platform.h b/plugins/platforms/x11/standalone/x11_platform.h --- a/plugins/platforms/x11/standalone/x11_platform.h +++ b/plugins/platforms/x11/standalone/x11_platform.h @@ -54,6 +54,7 @@ bool openGLCompositingIsBroken() const override; void createOpenGLSafePoint(OpenGLSafePoint safePoint) override; void startInteractiveWindowSelection(std::function callback, const QByteArray &cursorName = QByteArray()) override; + void startInteractivePositionSelection(std::function callback) override; PlatformCursorImage cursorImage() const override; diff --git a/plugins/platforms/x11/standalone/x11_platform.cpp b/plugins/platforms/x11/standalone/x11_platform.cpp --- a/plugins/platforms/x11/standalone/x11_platform.cpp +++ b/plugins/platforms/x11/standalone/x11_platform.cpp @@ -318,6 +318,14 @@ m_windowSelector->start(callback, cursorName); } +void X11StandalonePlatform::startInteractivePositionSelection(std::function callback) +{ + if (m_windowSelector.isNull()) { + m_windowSelector.reset(new WindowSelector); + } + m_windowSelector->start(callback); +} + void X11StandalonePlatform::setupActionForGlobalAccel(QAction *action) { connect(action, &QAction::triggered, kwinApp(), [action] {