diff --git a/backends/x11/x11windowed_backend.cpp b/backends/x11/x11windowed_backend.cpp index 9f88b83757..1db28ae77f 100644 --- a/backends/x11/x11windowed_backend.cpp +++ b/backends/x11/x11windowed_backend.cpp @@ -35,6 +35,8 @@ along with this program. If not, see . #include #include #include +// xcb +#include // system #include #include @@ -51,6 +53,9 @@ X11WindowedBackend::X11WindowedBackend(QObject *parent) X11WindowedBackend::~X11WindowedBackend() { if (m_connection) { + if (m_keySymbols) { + xcb_key_symbols_free(m_keySymbols); + } if (m_window) { xcb_unmap_window(m_connection, m_window); xcb_destroy_window(m_connection, m_window); @@ -121,7 +126,7 @@ void X11WindowedBackend::createWindow() m_winInfo = new NETWinInfo(m_connection, m_window, m_screen->root, NET::WMWindowType, NET::Properties2()); m_winInfo->setWindowType(NET::Normal); - m_winInfo->setName(i18n("KDE Wayland Compositor (%1)", waylandServer()->display()->socketName()).toUtf8().constData()); + updateWindowTitle(); m_winInfo->setPid(QCoreApplication::applicationPid()); QIcon windowIcon = QIcon::fromTheme(QStringLiteral("kwin")); auto addIcon = [this, &windowIcon] (const QSize &size) { @@ -179,6 +184,13 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e) case XCB_KEY_RELEASE: { auto event = reinterpret_cast(e); if (eventType == XCB_KEY_PRESS) { + if (!m_keySymbols) { + m_keySymbols = xcb_key_symbols_alloc(m_connection); + } + const xcb_keysym_t kc = xcb_key_symbols_get_keysym(m_keySymbols, event->detail, 0); + if (kc == XK_Control_R) { + grabKeyboard(event->time); + } keyboardKeyPressed(event->detail - 8, event->time); } else { keyboardKeyReleased(event->detail - 8, event->time); @@ -199,11 +211,60 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e) case XCB_EXPOSE: handleExpose(reinterpret_cast(e)); break; + case XCB_MAPPING_NOTIFY: + if (m_keySymbols) { + xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast(e)); + } + break; default: break; } } +void X11WindowedBackend::grabKeyboard(xcb_timestamp_t time) +{ + const bool oldState = m_keyboardGrabbed; + if (m_keyboardGrabbed) { + xcb_ungrab_keyboard(m_connection, time); + xcb_ungrab_pointer(m_connection, time); + m_keyboardGrabbed = false; + } else { + const auto c = xcb_grab_keyboard_unchecked(m_connection, false, m_window, time, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + ScopedCPointer grab(xcb_grab_keyboard_reply(m_connection, c, nullptr)); + if (grab.isNull()) { + return; + } + if (grab->status == XCB_GRAB_STATUS_SUCCESS) { + const auto c = xcb_grab_pointer_unchecked(m_connection, false, m_window, + 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, + m_window, XCB_CURSOR_NONE, time); + ScopedCPointer grab(xcb_grab_pointer_reply(m_connection, c, nullptr)); + if (grab.isNull() || grab->status != XCB_GRAB_STATUS_SUCCESS) { + xcb_ungrab_keyboard(m_connection, time); + return; + } + m_keyboardGrabbed = true; + } + } + if (oldState != m_keyboardGrabbed) { + updateWindowTitle(); + xcb_flush(m_connection); + } +} + +void X11WindowedBackend::updateWindowTitle() +{ + const QString grab = m_keyboardGrabbed ? i18n("Press right control to ungrab input") : i18n("Press right control key to grab input"); + const QString title = QStringLiteral("%1 (%2) - %3").arg(i18n("KDE Wayland Compositor")) + .arg(waylandServer()->display()->socketName()) + .arg(grab); + m_winInfo->setName(title.toUtf8().constData()); +} + void X11WindowedBackend::handleClientMessage(xcb_client_message_event_t *event) { if (event->window != m_window) { diff --git a/backends/x11/x11windowed_backend.h b/backends/x11/x11windowed_backend.h index c2ac8634aa..dc7c1564d2 100644 --- a/backends/x11/x11windowed_backend.h +++ b/backends/x11/x11windowed_backend.h @@ -30,6 +30,7 @@ along with this program. If not, see . struct _XDisplay; typedef struct _XDisplay Display; +typedef struct _XCBKeySymbols xcb_key_symbols_t; class NETWinInfo; namespace KWin @@ -78,6 +79,8 @@ Q_SIGNALS: private: void createWindow(); void startEventReading(); + void grabKeyboard(xcb_timestamp_t time); + void updateWindowTitle(); void handleEvent(xcb_generic_event_t *event); void handleClientMessage(xcb_client_message_event_t *event); void handleButtonPress(xcb_button_press_event_t *event); @@ -87,6 +90,7 @@ private: xcb_connection_t *m_connection = nullptr; xcb_screen_t *m_screen = nullptr; + xcb_key_symbols_t *m_keySymbols = nullptr; int m_screenNumber = 0; xcb_window_t m_window = XCB_WINDOW_NONE; QSize m_size; @@ -95,6 +99,7 @@ private: xcb_cursor_t m_cursor = XCB_CURSOR_NONE; Display *m_display = nullptr; NETWinInfo *m_winInfo = nullptr; + bool m_keyboardGrabbed = false; }; }