File indexing completed on 2024-11-10 04:56:37
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org> 0006 SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 #include "x11_windowed_backend.h" 0011 #include "../common/kwinxrenderutils.h" 0012 0013 #include <config-kwin.h> 0014 0015 #include "utils/xcbutils.h" 0016 #include "x11_windowed_egl_backend.h" 0017 #include "x11_windowed_logging.h" 0018 #include "x11_windowed_output.h" 0019 #include "x11_windowed_qpainter_backend.h" 0020 #include <pointer_input.h> 0021 // KDE 0022 #include <KLocalizedString> 0023 #include <QAbstractEventDispatcher> 0024 #include <QCoreApplication> 0025 #include <QSocketNotifier> 0026 // xcb 0027 #include <xcb/dri3.h> 0028 #include <xcb/xcb_keysyms.h> 0029 #include <xcb/present.h> 0030 #include <xcb/shm.h> 0031 // X11 0032 #include <X11/Xlib-xcb.h> 0033 #include <fixx11h.h> 0034 #if HAVE_X11_XINPUT 0035 #include <X11/extensions/XI2proto.h> 0036 #include <X11/extensions/XInput2.h> 0037 #endif 0038 // system 0039 #include <X11/Xlib-xcb.h> 0040 #include <X11/keysym.h> 0041 #include <drm_fourcc.h> 0042 #include <fcntl.h> 0043 #include <gbm.h> 0044 #include <linux/input.h> 0045 0046 namespace KWin 0047 { 0048 0049 void X11WindowedInputDevice::setPointer(bool set) 0050 { 0051 m_pointer = set; 0052 } 0053 0054 void X11WindowedInputDevice::setKeyboard(bool set) 0055 { 0056 m_keyboard = set; 0057 } 0058 0059 void X11WindowedInputDevice::setTouch(bool set) 0060 { 0061 m_touch = set; 0062 } 0063 0064 void X11WindowedInputDevice::setName(const QString &name) 0065 { 0066 m_name = name; 0067 } 0068 0069 QString X11WindowedInputDevice::sysName() const 0070 { 0071 return QString(); 0072 } 0073 0074 QString X11WindowedInputDevice::name() const 0075 { 0076 return m_name; 0077 } 0078 0079 bool X11WindowedInputDevice::isEnabled() const 0080 { 0081 return true; 0082 } 0083 0084 void X11WindowedInputDevice::setEnabled(bool enabled) 0085 { 0086 } 0087 0088 LEDs X11WindowedInputDevice::leds() const 0089 { 0090 return LEDs(); 0091 } 0092 0093 void X11WindowedInputDevice::setLeds(LEDs leds) 0094 { 0095 } 0096 0097 bool X11WindowedInputDevice::isKeyboard() const 0098 { 0099 return m_keyboard; 0100 } 0101 0102 bool X11WindowedInputDevice::isAlphaNumericKeyboard() const 0103 { 0104 return m_keyboard; 0105 } 0106 0107 bool X11WindowedInputDevice::isPointer() const 0108 { 0109 return m_pointer; 0110 } 0111 0112 bool X11WindowedInputDevice::isTouchpad() const 0113 { 0114 return false; 0115 } 0116 0117 bool X11WindowedInputDevice::isTouch() const 0118 { 0119 return m_touch; 0120 } 0121 0122 bool X11WindowedInputDevice::isTabletTool() const 0123 { 0124 return false; 0125 } 0126 0127 bool X11WindowedInputDevice::isTabletPad() const 0128 { 0129 return false; 0130 } 0131 0132 bool X11WindowedInputDevice::isTabletModeSwitch() const 0133 { 0134 return false; 0135 } 0136 0137 bool X11WindowedInputDevice::isLidSwitch() const 0138 { 0139 return false; 0140 } 0141 0142 X11WindowedInputBackend::X11WindowedInputBackend(X11WindowedBackend *backend) 0143 : m_backend(backend) 0144 { 0145 } 0146 0147 void X11WindowedInputBackend::initialize() 0148 { 0149 if (m_backend->pointerDevice()) { 0150 Q_EMIT deviceAdded(m_backend->pointerDevice()); 0151 } 0152 if (m_backend->keyboardDevice()) { 0153 Q_EMIT deviceAdded(m_backend->keyboardDevice()); 0154 } 0155 if (m_backend->touchDevice()) { 0156 Q_EMIT deviceAdded(m_backend->touchDevice()); 0157 } 0158 } 0159 0160 X11WindowedBackend::X11WindowedBackend(const X11WindowedBackendOptions &options) 0161 : m_options(options) 0162 { 0163 } 0164 0165 X11WindowedBackend::~X11WindowedBackend() 0166 { 0167 destroyOutputs(); 0168 m_pointerDevice.reset(); 0169 m_keyboardDevice.reset(); 0170 m_touchDevice.reset(); 0171 m_eglDisplay.reset(); 0172 0173 if (m_gbmDevice) { 0174 gbm_device_destroy(m_gbmDevice); 0175 } 0176 0177 if (m_connection) { 0178 if (m_keySymbols) { 0179 xcb_key_symbols_free(m_keySymbols); 0180 } 0181 xcb_disconnect(m_connection); 0182 m_connection = nullptr; 0183 } 0184 } 0185 0186 bool X11WindowedBackend::initialize() 0187 { 0188 m_display = XOpenDisplay(m_options.display.toLatin1().constData()); 0189 if (!m_display) { 0190 return false; 0191 } 0192 0193 m_connection = XGetXCBConnection(m_display); 0194 m_screenNumber = XDefaultScreen(m_display); 0195 XSetEventQueueOwner(m_display, XCBOwnsEventQueue); 0196 0197 int screen = m_screenNumber; 0198 for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection)); 0199 it.rem; 0200 --screen, xcb_screen_next(&it)) { 0201 if (screen == m_screenNumber) { 0202 m_screen = it.data; 0203 } 0204 } 0205 0206 const xcb_query_extension_reply_t *presentExtension = xcb_get_extension_data(m_connection, &xcb_present_id); 0207 if (presentExtension && presentExtension->present) { 0208 m_presentOpcode = presentExtension->major_opcode; 0209 xcb_present_query_version_cookie_t cookie = xcb_present_query_version(m_connection, 1, 2); 0210 UniqueCPtr<xcb_present_query_version_reply_t> reply(xcb_present_query_version_reply(m_connection, cookie, nullptr)); 0211 if (!reply) { 0212 qCWarning(KWIN_X11WINDOWED) << "Requested Present extension version is unsupported"; 0213 return false; 0214 } 0215 m_presentMajorVersion = reply->major_version; 0216 m_presentMinorVersion = reply->minor_version; 0217 } else { 0218 qCWarning(KWIN_X11WINDOWED) << "Present X11 extension is unavailable"; 0219 return false; 0220 } 0221 0222 const xcb_query_extension_reply_t *shmExtension = xcb_get_extension_data(m_connection, &xcb_shm_id); 0223 if (shmExtension && shmExtension->present) { 0224 xcb_shm_query_version_cookie_t cookie = xcb_shm_query_version(m_connection); 0225 UniqueCPtr<xcb_shm_query_version_reply_t> reply(xcb_shm_query_version_reply(m_connection, cookie, nullptr)); 0226 if (!reply) { 0227 qCWarning(KWIN_X11WINDOWED) << "Requested SHM extension version is unsupported"; 0228 } else { 0229 if (!reply->shared_pixmaps) { 0230 qCWarning(KWIN_X11WINDOWED) << "X server supports SHM extension but not shared pixmaps"; 0231 } else { 0232 m_hasShm = true; 0233 } 0234 } 0235 } 0236 0237 const xcb_query_extension_reply_t *driExtension = xcb_get_extension_data(m_connection, &xcb_dri3_id); 0238 if (driExtension && driExtension->present) { 0239 xcb_dri3_query_version_cookie_t cookie = xcb_dri3_query_version(m_connection, 1, 2); 0240 UniqueCPtr<xcb_dri3_query_version_reply_t> reply(xcb_dri3_query_version_reply(m_connection, cookie, nullptr)); 0241 if (reply) { 0242 m_hasDri = true; 0243 m_driMajorVersion = reply->major_version; 0244 m_driMinorVersion = reply->minor_version; 0245 } else { 0246 qCWarning(KWIN_X11WINDOWED) << "Requested DRI3 extension version is unsupported"; 0247 } 0248 } 0249 0250 initXInput(); 0251 initDri3(); 0252 0253 XRenderUtils::init(m_connection, m_screen->root); 0254 createOutputs(); 0255 0256 m_pointerDevice = std::make_unique<X11WindowedInputDevice>(); 0257 m_pointerDevice->setPointer(true); 0258 m_keyboardDevice = std::make_unique<X11WindowedInputDevice>(); 0259 m_keyboardDevice->setKeyboard(true); 0260 if (m_hasXInput) { 0261 m_touchDevice = std::make_unique<X11WindowedInputDevice>(); 0262 m_touchDevice->setTouch(true); 0263 } 0264 0265 m_eventNotifier = std::make_unique<QSocketNotifier>(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read); 0266 auto processXcbEvents = [this] { 0267 while (auto event = xcb_poll_for_event(m_connection)) { 0268 handleEvent(event); 0269 free(event); 0270 } 0271 xcb_flush(m_connection); 0272 }; 0273 connect(m_eventNotifier.get(), &QSocketNotifier::activated, this, processXcbEvents); 0274 connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, processXcbEvents); 0275 connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::awake, this, processXcbEvents); 0276 0277 Q_EMIT outputsQueried(); 0278 return true; 0279 } 0280 0281 void X11WindowedBackend::initXInput() 0282 { 0283 #if HAVE_X11_XINPUT 0284 int xi_opcode, event, error; 0285 // init XInput extension 0286 if (!XQueryExtension(m_display, "XInputExtension", &xi_opcode, &event, &error)) { 0287 qCDebug(KWIN_X11WINDOWED) << "XInputExtension not present"; 0288 return; 0289 } 0290 0291 // verify that the XInput extension is at at least version 2.0 0292 int major = 2, minor = 2; 0293 int result = XIQueryVersion(m_display, &major, &minor); 0294 if (result != Success) { 0295 qCDebug(KWIN_X11WINDOWED) << "Failed to init XInput 2.2, trying 2.0"; 0296 minor = 0; 0297 if (XIQueryVersion(m_display, &major, &minor) != Success) { 0298 qCDebug(KWIN_X11WINDOWED) << "Failed to init XInput"; 0299 return; 0300 } 0301 } 0302 m_xiOpcode = xi_opcode; 0303 m_majorVersion = major; 0304 m_minorVersion = minor; 0305 m_hasXInput = m_majorVersion >= 2 && m_minorVersion >= 2; 0306 #endif 0307 } 0308 0309 void X11WindowedBackend::initDri3() 0310 { 0311 if (m_hasDri) { 0312 xcb_dri3_open_cookie_t cookie = xcb_dri3_open(m_connection, m_screen->root, 0); 0313 UniqueCPtr<xcb_dri3_open_reply_t> reply(xcb_dri3_open_reply(m_connection, cookie, nullptr)); 0314 if (reply && reply->nfd == 1) { 0315 int fd = xcb_dri3_open_reply_fds(m_connection, reply.get())[0]; 0316 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 0317 m_drmFileDescriptor = FileDescriptor{fd}; 0318 m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get()); 0319 } 0320 } 0321 0322 xcb_depth_iterator_t it = xcb_screen_allowed_depths_iterator(m_screen); 0323 while (it.rem > 0) { 0324 uint32_t format = driFormatForDepth(it.data->depth); 0325 if (format) { 0326 QList<uint64_t> &mods = m_driFormats[format]; 0327 0328 if (m_driMajorVersion > 1 || m_driMinorVersion >= 2) { 0329 xcb_dri3_get_supported_modifiers_cookie_t cookie = xcb_dri3_get_supported_modifiers(m_connection, m_screen->root, it.data->depth, 32); 0330 UniqueCPtr<xcb_dri3_get_supported_modifiers_reply_t> reply(xcb_dri3_get_supported_modifiers_reply(m_connection, cookie, nullptr)); 0331 if (reply) { 0332 const uint64_t *modifiers = xcb_dri3_get_supported_modifiers_screen_modifiers(reply.get()); 0333 const int modifierCount = xcb_dri3_get_supported_modifiers_screen_modifiers_length(reply.get()); 0334 for (int i = 0; i < modifierCount; ++i) { 0335 mods.append(modifiers[i]); 0336 } 0337 } 0338 } 0339 0340 if (mods.isEmpty()) { 0341 mods.append(DRM_FORMAT_MOD_INVALID); 0342 } 0343 } 0344 0345 xcb_depth_next(&it); 0346 } 0347 } 0348 0349 X11WindowedOutput *X11WindowedBackend::findOutput(xcb_window_t window) const 0350 { 0351 auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), 0352 [window](X11WindowedOutput *output) { 0353 return output->window() == window; 0354 }); 0355 if (it != m_outputs.constEnd()) { 0356 return *it; 0357 } 0358 return nullptr; 0359 } 0360 0361 void X11WindowedBackend::createOutputs() 0362 { 0363 Xcb::Atom protocolsAtom(QByteArrayLiteral("WM_PROTOCOLS"), false, m_connection); 0364 Xcb::Atom deleteWindowAtom(QByteArrayLiteral("WM_DELETE_WINDOW"), false, m_connection); 0365 0366 // we need to multiply the initial window size with the scale in order to 0367 // create an output window of this size in the end 0368 const QSize pixelSize = m_options.outputSize * m_options.outputScale; 0369 for (int i = 0; i < m_options.outputCount; ++i) { 0370 auto *output = new X11WindowedOutput(this); 0371 output->init(pixelSize, m_options.outputScale); 0372 0373 m_protocols = protocolsAtom; 0374 m_deleteWindowProtocol = deleteWindowAtom; 0375 0376 xcb_change_property(m_connection, 0377 XCB_PROP_MODE_REPLACE, 0378 output->window(), 0379 m_protocols, 0380 XCB_ATOM_ATOM, 0381 32, 1, 0382 &m_deleteWindowProtocol); 0383 0384 m_outputs << output; 0385 Q_EMIT outputAdded(output); 0386 output->updateEnabled(true); 0387 } 0388 0389 updateWindowTitle(); 0390 0391 xcb_flush(m_connection); 0392 } 0393 0394 #if HAVE_X11_XINPUT 0395 0396 static inline qreal fixed1616ToReal(FP1616 val) 0397 { 0398 return (val)*1.0 / (1 << 16); 0399 } 0400 #endif 0401 0402 void X11WindowedBackend::handleEvent(xcb_generic_event_t *e) 0403 { 0404 const uint8_t eventType = e->response_type & ~0x80; 0405 switch (eventType) { 0406 case XCB_BUTTON_PRESS: 0407 case XCB_BUTTON_RELEASE: 0408 handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(e)); 0409 break; 0410 case XCB_MOTION_NOTIFY: { 0411 auto event = reinterpret_cast<xcb_motion_notify_event_t *>(e); 0412 const X11WindowedOutput *output = findOutput(event->event); 0413 if (!output) { 0414 break; 0415 } 0416 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y)); 0417 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get()); 0418 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get()); 0419 } break; 0420 case XCB_KEY_PRESS: 0421 case XCB_KEY_RELEASE: { 0422 auto event = reinterpret_cast<xcb_key_press_event_t *>(e); 0423 if (eventType == XCB_KEY_PRESS) { 0424 if (!m_keySymbols) { 0425 m_keySymbols = xcb_key_symbols_alloc(m_connection); 0426 } 0427 const xcb_keysym_t kc = xcb_key_symbols_get_keysym(m_keySymbols, event->detail, 0); 0428 if (kc == XK_Control_R) { 0429 grabKeyboard(event->time); 0430 } 0431 Q_EMIT m_keyboardDevice->keyChanged(event->detail - 8, 0432 InputRedirection::KeyboardKeyPressed, 0433 std::chrono::milliseconds(event->time), 0434 m_keyboardDevice.get()); 0435 } else { 0436 Q_EMIT m_keyboardDevice->keyChanged(event->detail - 8, 0437 InputRedirection::KeyboardKeyReleased, 0438 std::chrono::milliseconds(event->time), 0439 m_keyboardDevice.get()); 0440 } 0441 } break; 0442 case XCB_CONFIGURE_NOTIFY: 0443 updateSize(reinterpret_cast<xcb_configure_notify_event_t *>(e)); 0444 break; 0445 case XCB_ENTER_NOTIFY: { 0446 auto event = reinterpret_cast<xcb_enter_notify_event_t *>(e); 0447 const X11WindowedOutput *output = findOutput(event->event); 0448 if (!output) { 0449 break; 0450 } 0451 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y)); 0452 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get()); 0453 } break; 0454 case XCB_CLIENT_MESSAGE: 0455 handleClientMessage(reinterpret_cast<xcb_client_message_event_t *>(e)); 0456 break; 0457 case XCB_EXPOSE: 0458 handleExpose(reinterpret_cast<xcb_expose_event_t *>(e)); 0459 break; 0460 case XCB_MAPPING_NOTIFY: 0461 if (m_keySymbols) { 0462 xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast<xcb_mapping_notify_event_t *>(e)); 0463 } 0464 break; 0465 case XCB_GE_GENERIC: { 0466 xcb_ge_generic_event_t *ev = reinterpret_cast<xcb_ge_generic_event_t *>(e); 0467 if (ev->extension == m_presentOpcode) { 0468 handlePresentEvent(ev); 0469 } else if (ev->extension == m_xiOpcode) { 0470 handleXinputEvent(ev); 0471 } 0472 break; 0473 } 0474 default: 0475 break; 0476 } 0477 } 0478 0479 void X11WindowedBackend::grabKeyboard(xcb_timestamp_t time) 0480 { 0481 const bool oldState = m_keyboardGrabbed; 0482 if (m_keyboardGrabbed) { 0483 xcb_ungrab_keyboard(m_connection, time); 0484 xcb_ungrab_pointer(m_connection, time); 0485 m_keyboardGrabbed = false; 0486 } else { 0487 const X11WindowedOutput *output = static_cast<X11WindowedOutput *>(m_outputs[0]); 0488 const auto c = xcb_grab_keyboard_unchecked(m_connection, false, output->window(), time, 0489 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 0490 UniqueCPtr<xcb_grab_keyboard_reply_t> grab(xcb_grab_keyboard_reply(m_connection, c, nullptr)); 0491 if (!grab) { 0492 return; 0493 } 0494 if (grab->status == XCB_GRAB_STATUS_SUCCESS) { 0495 const auto c = xcb_grab_pointer_unchecked(m_connection, false, output->window(), 0496 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, 0497 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, 0498 output->window(), XCB_CURSOR_NONE, time); 0499 UniqueCPtr<xcb_grab_pointer_reply_t> grab(xcb_grab_pointer_reply(m_connection, c, nullptr)); 0500 if (!grab || grab->status != XCB_GRAB_STATUS_SUCCESS) { 0501 xcb_ungrab_keyboard(m_connection, time); 0502 return; 0503 } 0504 m_keyboardGrabbed = true; 0505 } 0506 } 0507 if (oldState != m_keyboardGrabbed) { 0508 updateWindowTitle(); 0509 xcb_flush(m_connection); 0510 } 0511 } 0512 0513 void X11WindowedBackend::updateWindowTitle() 0514 { 0515 const QString grab = m_keyboardGrabbed ? i18n("Press right control to ungrab input") : i18n("Press right control key to grab input"); 0516 const QString title = QStringLiteral("%1 - %2").arg(i18n("KDE Wayland Compositor"), grab); 0517 for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { 0518 (*it)->setWindowTitle(title); 0519 } 0520 } 0521 0522 void X11WindowedBackend::handleClientMessage(xcb_client_message_event_t *event) 0523 { 0524 auto it = std::find_if(m_outputs.begin(), m_outputs.end(), 0525 [event](X11WindowedOutput *output) { 0526 return output->window() == event->window; 0527 }); 0528 if (it == m_outputs.end()) { 0529 return; 0530 } 0531 if (event->type == m_protocols && m_protocols != XCB_ATOM_NONE) { 0532 if (event->data.data32[0] == m_deleteWindowProtocol && m_deleteWindowProtocol != XCB_ATOM_NONE) { 0533 if (m_outputs.count() == 1) { 0534 qCDebug(KWIN_X11WINDOWED) << "Backend window is going to be closed, shutting down."; 0535 QCoreApplication::quit(); 0536 } else { 0537 // remove the window 0538 qCDebug(KWIN_X11WINDOWED) << "Removing one output window."; 0539 0540 auto removedOutput = *it; 0541 it = m_outputs.erase(it); 0542 0543 removedOutput->updateEnabled(false); 0544 Q_EMIT outputRemoved(removedOutput); 0545 removedOutput->unref(); 0546 Q_EMIT outputsQueried(); 0547 } 0548 } 0549 } 0550 } 0551 0552 void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event) 0553 { 0554 const X11WindowedOutput *output = findOutput(event->event); 0555 if (!output) { 0556 return; 0557 } 0558 bool const pressed = (event->response_type & ~0x80) == XCB_BUTTON_PRESS; 0559 if (event->detail >= XCB_BUTTON_INDEX_4 && event->detail <= 7) { 0560 // wheel 0561 if (!pressed) { 0562 return; 0563 } 0564 const int delta = (event->detail == XCB_BUTTON_INDEX_4 || event->detail == 6) ? -120 : 120; 0565 static const qreal s_defaultAxisStepDistance = 10.0; 0566 InputRedirection::PointerAxis axis; 0567 if (event->detail > 5) { 0568 axis = InputRedirection::PointerAxisHorizontal; 0569 } else { 0570 axis = InputRedirection::PointerAxisVertical; 0571 } 0572 Q_EMIT m_pointerDevice->pointerAxisChanged(axis, 0573 delta * s_defaultAxisStepDistance, 0574 delta, 0575 InputRedirection::PointerAxisSourceUnknown, 0576 std::chrono::milliseconds(event->time), 0577 m_pointerDevice.get()); 0578 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get()); 0579 return; 0580 } 0581 uint32_t button = 0; 0582 switch (event->detail) { 0583 case XCB_BUTTON_INDEX_1: 0584 button = BTN_LEFT; 0585 break; 0586 case XCB_BUTTON_INDEX_2: 0587 button = BTN_MIDDLE; 0588 break; 0589 case XCB_BUTTON_INDEX_3: 0590 button = BTN_RIGHT; 0591 break; 0592 default: 0593 button = event->detail + BTN_LEFT - 1; 0594 return; 0595 } 0596 0597 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y)); 0598 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get()); 0599 0600 if (pressed) { 0601 Q_EMIT m_pointerDevice->pointerButtonChanged(button, InputRedirection::PointerButtonPressed, std::chrono::milliseconds(event->time), m_pointerDevice.get()); 0602 } else { 0603 Q_EMIT m_pointerDevice->pointerButtonChanged(button, InputRedirection::PointerButtonReleased, std::chrono::milliseconds(event->time), m_pointerDevice.get()); 0604 } 0605 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get()); 0606 } 0607 0608 void X11WindowedBackend::handleExpose(xcb_expose_event_t *event) 0609 { 0610 X11WindowedOutput *output = findOutput(event->window); 0611 if (output) { 0612 output->addExposedArea(QRect(event->x, event->y, event->width, event->height)); 0613 output->renderLoop()->scheduleRepaint(); 0614 } 0615 } 0616 0617 void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event) 0618 { 0619 X11WindowedOutput *output = findOutput(event->window); 0620 if (!output) { 0621 return; 0622 } 0623 0624 output->setHostPosition(QPoint(event->x, event->y)); 0625 0626 const QSize s = QSize(event->width, event->height); 0627 if (s != output->pixelSize()) { 0628 output->resize(s); 0629 } 0630 } 0631 0632 void X11WindowedBackend::handleXinputEvent(xcb_ge_generic_event_t *ge) 0633 { 0634 #if HAVE_X11_XINPUT 0635 auto te = reinterpret_cast<xXIDeviceEvent *>(ge); 0636 const X11WindowedOutput *output = findOutput(te->event); 0637 if (!output) { 0638 return; 0639 } 0640 0641 const QPointF position = output->mapFromGlobal(QPointF(fixed1616ToReal(te->root_x), fixed1616ToReal(te->root_y))); 0642 0643 switch (ge->event_type) { 0644 case XI_TouchBegin: { 0645 Q_EMIT m_touchDevice->touchDown(te->detail, position, std::chrono::milliseconds(te->time), m_touchDevice.get()); 0646 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); 0647 break; 0648 } 0649 case XI_TouchUpdate: { 0650 Q_EMIT m_touchDevice->touchMotion(te->detail, position, std::chrono::milliseconds(te->time), m_touchDevice.get()); 0651 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); 0652 break; 0653 } 0654 case XI_TouchEnd: { 0655 Q_EMIT m_touchDevice->touchUp(te->detail, std::chrono::milliseconds(te->time), m_touchDevice.get()); 0656 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get()); 0657 break; 0658 } 0659 case XI_TouchOwnership: { 0660 auto te = reinterpret_cast<xXITouchOwnershipEvent *>(ge); 0661 XIAllowTouchEvents(m_display, te->deviceid, te->sourceid, te->touchid, XIAcceptTouch); 0662 break; 0663 } 0664 } 0665 #endif 0666 } 0667 0668 void X11WindowedBackend::handlePresentEvent(xcb_ge_generic_event_t *ge) 0669 { 0670 switch (ge->event_type) { 0671 case XCB_PRESENT_EVENT_IDLE_NOTIFY: { 0672 xcb_present_idle_notify_event_t *idleNotify = reinterpret_cast<xcb_present_idle_notify_event_t *>(ge); 0673 if (X11WindowedOutput *output = findOutput(idleNotify->window)) { 0674 output->handlePresentIdleNotify(idleNotify); 0675 } 0676 break; 0677 } 0678 case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: { 0679 xcb_present_complete_notify_event_t *completeNotify = reinterpret_cast<xcb_present_complete_notify_event_t *>(ge); 0680 if (X11WindowedOutput *output = findOutput(completeNotify->window)) { 0681 output->handlePresentCompleteNotify(completeNotify); 0682 } 0683 break; 0684 } 0685 } 0686 } 0687 0688 xcb_window_t X11WindowedBackend::rootWindow() const 0689 { 0690 if (!m_screen) { 0691 return XCB_WINDOW_NONE; 0692 } 0693 return m_screen->root; 0694 } 0695 0696 gbm_device *X11WindowedBackend::gbmDevice() const 0697 { 0698 return m_gbmDevice; 0699 } 0700 0701 X11WindowedInputDevice *X11WindowedBackend::pointerDevice() const 0702 { 0703 return m_pointerDevice.get(); 0704 } 0705 0706 X11WindowedInputDevice *X11WindowedBackend::keyboardDevice() const 0707 { 0708 return m_keyboardDevice.get(); 0709 } 0710 0711 X11WindowedInputDevice *X11WindowedBackend::touchDevice() const 0712 { 0713 return m_touchDevice.get(); 0714 } 0715 0716 std::unique_ptr<OpenGLBackend> X11WindowedBackend::createOpenGLBackend() 0717 { 0718 return std::make_unique<X11WindowedEglBackend>(this); 0719 } 0720 0721 std::unique_ptr<QPainterBackend> X11WindowedBackend::createQPainterBackend() 0722 { 0723 return std::make_unique<X11WindowedQPainterBackend>(this); 0724 } 0725 0726 std::unique_ptr<InputBackend> X11WindowedBackend::createInputBackend() 0727 { 0728 return std::make_unique<X11WindowedInputBackend>(this); 0729 } 0730 0731 xcb_connection_t *X11WindowedBackend::connection() const 0732 { 0733 return m_connection; 0734 } 0735 0736 xcb_screen_t *X11WindowedBackend::screen() const 0737 { 0738 return m_screen; 0739 } 0740 0741 int X11WindowedBackend::screenNumer() const 0742 { 0743 return m_screenNumber; 0744 } 0745 0746 ::Display *X11WindowedBackend::display() const 0747 { 0748 return m_display; 0749 } 0750 0751 bool X11WindowedBackend::hasXInput() const 0752 { 0753 return m_hasXInput; 0754 } 0755 0756 QHash<uint32_t, QList<uint64_t>> X11WindowedBackend::driFormats() const 0757 { 0758 return m_driFormats; 0759 } 0760 0761 uint32_t X11WindowedBackend::driFormatForDepth(int depth) const 0762 { 0763 switch (depth) { 0764 case 24: 0765 return DRM_FORMAT_XRGB8888; 0766 case 32: 0767 return DRM_FORMAT_ARGB8888; 0768 default: 0769 return 0; 0770 } 0771 } 0772 0773 int X11WindowedBackend::driMajorVersion() const 0774 { 0775 return m_driMajorVersion; 0776 } 0777 0778 int X11WindowedBackend::driMinorVersion() const 0779 { 0780 return m_driMinorVersion; 0781 } 0782 0783 QList<CompositingType> X11WindowedBackend::supportedCompositors() const 0784 { 0785 QList<CompositingType> ret; 0786 if (m_gbmDevice) { 0787 ret.append(OpenGLCompositing); 0788 } 0789 if (m_hasShm) { 0790 ret.append(QPainterCompositing); 0791 } 0792 return ret; 0793 } 0794 0795 Outputs X11WindowedBackend::outputs() const 0796 { 0797 return m_outputs; 0798 } 0799 0800 void X11WindowedBackend::destroyOutputs() 0801 { 0802 while (!m_outputs.isEmpty()) { 0803 auto output = m_outputs.takeLast(); 0804 output->updateEnabled(false); 0805 Q_EMIT outputRemoved(output); 0806 delete output; 0807 } 0808 } 0809 0810 void X11WindowedBackend::setEglDisplay(std::unique_ptr<EglDisplay> &&display) 0811 { 0812 m_eglDisplay = std::move(display); 0813 } 0814 0815 EglDisplay *X11WindowedBackend::sceneEglDisplayObject() const 0816 { 0817 return m_eglDisplay.get(); 0818 } 0819 0820 } // namespace KWin 0821 0822 #include "moc_x11_windowed_backend.cpp"