[backends/x11] Allow grab keyboard/pointer
When pressing right control key the input gets grabbed/released. The grab is for both keyboard and pointer and pointer is also confined to the window. How to grab/ungrab is added to the window title.
This commit is contained in:
parent
4fa01583cb
commit
e5fbb20e8b
2 changed files with 67 additions and 1 deletions
backends/x11
|
@ -35,6 +35,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KWayland/Server/display.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
// xcb
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
// system
|
||||
#include <linux/input.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
|
@ -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<xcb_key_press_event_t*>(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<xcb_expose_event_t*>(e));
|
||||
break;
|
||||
case XCB_MAPPING_NOTIFY:
|
||||
if (m_keySymbols) {
|
||||
xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast<xcb_mapping_notify_event_t*>(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<xcb_grab_keyboard_reply_t> 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<xcb_grab_pointer_reply_t> 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) {
|
||||
|
|
|
@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue