KWin
Loading...
Searching...
No Matches
x11_windowed_backend.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
6 SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
12
13#include <config-kwin.h>
14
15#include "utils/xcbutils.h"
18#include "x11_windowed_output.h"
20#include <pointer_input.h>
21// KDE
22#include <KLocalizedString>
23#include <QAbstractEventDispatcher>
24#include <QCoreApplication>
25#include <QSocketNotifier>
26// xcb
27#include <xcb/dri3.h>
28#include <xcb/xcb_keysyms.h>
29#include <xcb/present.h>
30#include <xcb/shm.h>
31// X11
32#include <X11/Xlib-xcb.h>
33#include <fixx11h.h>
34#if HAVE_X11_XINPUT
35#include <X11/extensions/XI2proto.h>
36#include <X11/extensions/XInput2.h>
37#endif
38// system
39#include <X11/Xlib-xcb.h>
40#include <X11/keysym.h>
41#include <drm_fourcc.h>
42#include <fcntl.h>
43#include <gbm.h>
44#include <linux/input.h>
45
46namespace KWin
47{
48
50{
51 m_pointer = set;
52}
53
55{
56 m_keyboard = set;
57}
58
60{
61 m_touch = set;
62}
63
64void X11WindowedInputDevice::setName(const QString &name)
65{
66 m_name = name;
67}
68
70{
71 return QString();
72}
73
75{
76 return m_name;
77}
78
80{
81 return true;
82}
83
85{
86}
87
89{
90 return LEDs();
91}
92
94{
95}
96
98{
99 return m_keyboard;
100}
101
103{
104 return m_pointer;
105}
106
108{
109 return false;
110}
111
113{
114 return m_touch;
115}
116
118{
119 return false;
120}
121
123{
124 return false;
125}
126
128{
129 return false;
130}
131
133{
134 return false;
135}
136
138 : m_backend(backend)
139{
140}
141
143{
144 if (m_backend->pointerDevice()) {
145 Q_EMIT deviceAdded(m_backend->pointerDevice());
146 }
147 if (m_backend->keyboardDevice()) {
148 Q_EMIT deviceAdded(m_backend->keyboardDevice());
149 }
150 if (m_backend->touchDevice()) {
151 Q_EMIT deviceAdded(m_backend->touchDevice());
152 }
153}
154
159
161{
162 destroyOutputs();
163 m_pointerDevice.reset();
164 m_keyboardDevice.reset();
165 m_touchDevice.reset();
166 m_eglDisplay.reset();
167
168 if (m_gbmDevice) {
169 gbm_device_destroy(m_gbmDevice);
170 }
171
172 if (m_connection) {
173 if (m_keySymbols) {
174 xcb_key_symbols_free(m_keySymbols);
175 }
176 xcb_disconnect(m_connection);
177 m_connection = nullptr;
178 }
179}
180
182{
183 m_display = XOpenDisplay(m_options.display.toLatin1().constData());
184 if (!m_display) {
185 return false;
186 }
187
188 m_connection = XGetXCBConnection(m_display);
189 m_screenNumber = XDefaultScreen(m_display);
190 XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
191
192 int screen = m_screenNumber;
193 for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection));
194 it.rem;
195 --screen, xcb_screen_next(&it)) {
196 if (screen == m_screenNumber) {
197 m_screen = it.data;
198 }
199 }
200
201 const xcb_query_extension_reply_t *presentExtension = xcb_get_extension_data(m_connection, &xcb_present_id);
202 if (presentExtension && presentExtension->present) {
203 m_presentOpcode = presentExtension->major_opcode;
204 xcb_present_query_version_cookie_t cookie = xcb_present_query_version(m_connection, 1, 2);
205 UniqueCPtr<xcb_present_query_version_reply_t> reply(xcb_present_query_version_reply(m_connection, cookie, nullptr));
206 if (!reply) {
207 qCWarning(KWIN_X11WINDOWED) << "Requested Present extension version is unsupported";
208 return false;
209 }
210 m_presentMajorVersion = reply->major_version;
211 m_presentMinorVersion = reply->minor_version;
212 } else {
213 qCWarning(KWIN_X11WINDOWED) << "Present X11 extension is unavailable";
214 return false;
215 }
216
217 const xcb_query_extension_reply_t *shmExtension = xcb_get_extension_data(m_connection, &xcb_shm_id);
218 if (shmExtension && shmExtension->present) {
219 xcb_shm_query_version_cookie_t cookie = xcb_shm_query_version(m_connection);
220 UniqueCPtr<xcb_shm_query_version_reply_t> reply(xcb_shm_query_version_reply(m_connection, cookie, nullptr));
221 if (!reply) {
222 qCWarning(KWIN_X11WINDOWED) << "Requested SHM extension version is unsupported";
223 } else {
224 if (!reply->shared_pixmaps) {
225 qCWarning(KWIN_X11WINDOWED) << "X server supports SHM extension but not shared pixmaps";
226 } else {
227 m_hasShm = true;
228 }
229 }
230 }
231
232 const xcb_query_extension_reply_t *driExtension = xcb_get_extension_data(m_connection, &xcb_dri3_id);
233 if (driExtension && driExtension->present) {
234 xcb_dri3_query_version_cookie_t cookie = xcb_dri3_query_version(m_connection, 1, 2);
235 UniqueCPtr<xcb_dri3_query_version_reply_t> reply(xcb_dri3_query_version_reply(m_connection, cookie, nullptr));
236 if (reply) {
237 m_hasDri = true;
238 m_driMajorVersion = reply->major_version;
239 m_driMinorVersion = reply->minor_version;
240 } else {
241 qCWarning(KWIN_X11WINDOWED) << "Requested DRI3 extension version is unsupported";
242 }
243 }
244
245 initXInput();
246 initDri3();
247
248 XRenderUtils::init(m_connection, m_screen->root);
249 createOutputs();
250
251 m_pointerDevice = std::make_unique<X11WindowedInputDevice>();
252 m_pointerDevice->setPointer(true);
253 m_keyboardDevice = std::make_unique<X11WindowedInputDevice>();
254 m_keyboardDevice->setKeyboard(true);
255 if (m_hasXInput) {
256 m_touchDevice = std::make_unique<X11WindowedInputDevice>();
257 m_touchDevice->setTouch(true);
258 }
259
260 m_eventNotifier = std::make_unique<QSocketNotifier>(xcb_get_file_descriptor(m_connection), QSocketNotifier::Read);
261 auto processXcbEvents = [this] {
262 while (auto event = xcb_poll_for_event(m_connection)) {
263 handleEvent(event);
264 free(event);
265 }
266 xcb_flush(m_connection);
267 };
268 connect(m_eventNotifier.get(), &QSocketNotifier::activated, this, processXcbEvents);
269 connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, processXcbEvents);
270 connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::awake, this, processXcbEvents);
271
272 Q_EMIT outputsQueried();
273 return true;
274}
275
276void X11WindowedBackend::initXInput()
277{
278#if HAVE_X11_XINPUT
279 int xi_opcode, event, error;
280 // init XInput extension
281 if (!XQueryExtension(m_display, "XInputExtension", &xi_opcode, &event, &error)) {
282 qCDebug(KWIN_X11WINDOWED) << "XInputExtension not present";
283 return;
284 }
285
286 // verify that the XInput extension is at at least version 2.0
287 int major = 2, minor = 2;
288 int result = XIQueryVersion(m_display, &major, &minor);
289 if (result != Success) {
290 qCDebug(KWIN_X11WINDOWED) << "Failed to init XInput 2.2, trying 2.0";
291 minor = 0;
292 if (XIQueryVersion(m_display, &major, &minor) != Success) {
293 qCDebug(KWIN_X11WINDOWED) << "Failed to init XInput";
294 return;
295 }
296 }
297 m_xiOpcode = xi_opcode;
298 m_majorVersion = major;
299 m_minorVersion = minor;
300 m_hasXInput = m_majorVersion >= 2 && m_minorVersion >= 2;
301#endif
302}
303
304void X11WindowedBackend::initDri3()
305{
306 if (m_hasDri) {
307 xcb_dri3_open_cookie_t cookie = xcb_dri3_open(m_connection, m_screen->root, 0);
308 UniqueCPtr<xcb_dri3_open_reply_t> reply(xcb_dri3_open_reply(m_connection, cookie, nullptr));
309 if (reply && reply->nfd == 1) {
310 int fd = xcb_dri3_open_reply_fds(m_connection, reply.get())[0];
311 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
312 m_drmFileDescriptor = FileDescriptor{fd};
313 m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get());
314 }
315 }
316
317 xcb_depth_iterator_t it = xcb_screen_allowed_depths_iterator(m_screen);
318 while (it.rem > 0) {
319 uint32_t format = driFormatForDepth(it.data->depth);
320 if (format) {
321 QList<uint64_t> &mods = m_driFormats[format];
322
323 if (m_driMajorVersion > 1 || m_driMinorVersion >= 2) {
324 xcb_dri3_get_supported_modifiers_cookie_t cookie = xcb_dri3_get_supported_modifiers(m_connection, m_screen->root, it.data->depth, 32);
325 UniqueCPtr<xcb_dri3_get_supported_modifiers_reply_t> reply(xcb_dri3_get_supported_modifiers_reply(m_connection, cookie, nullptr));
326 if (reply) {
327 const uint64_t *modifiers = xcb_dri3_get_supported_modifiers_screen_modifiers(reply.get());
328 const int modifierCount = xcb_dri3_get_supported_modifiers_screen_modifiers_length(reply.get());
329 for (int i = 0; i < modifierCount; ++i) {
330 mods.append(modifiers[i]);
331 }
332 }
333 }
334
335 if (mods.isEmpty()) {
336 mods.append(DRM_FORMAT_MOD_INVALID);
337 }
338 }
339
340 xcb_depth_next(&it);
341 }
342}
343
344X11WindowedOutput *X11WindowedBackend::findOutput(xcb_window_t window) const
345{
346 auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(),
347 [window](X11WindowedOutput *output) {
348 return output->window() == window;
349 });
350 if (it != m_outputs.constEnd()) {
351 return *it;
352 }
353 return nullptr;
354}
355
356void X11WindowedBackend::createOutputs()
357{
358 Xcb::Atom protocolsAtom(QByteArrayLiteral("WM_PROTOCOLS"), false, m_connection);
359 Xcb::Atom deleteWindowAtom(QByteArrayLiteral("WM_DELETE_WINDOW"), false, m_connection);
360
361 // we need to multiply the initial window size with the scale in order to
362 // create an output window of this size in the end
363 const QSize pixelSize = m_options.outputSize * m_options.outputScale;
364 for (int i = 0; i < m_options.outputCount; ++i) {
365 auto *output = new X11WindowedOutput(this);
366 output->init(pixelSize, m_options.outputScale);
367
368 m_protocols = protocolsAtom;
369 m_deleteWindowProtocol = deleteWindowAtom;
370
371 xcb_change_property(m_connection,
372 XCB_PROP_MODE_REPLACE,
373 output->window(),
374 m_protocols,
375 XCB_ATOM_ATOM,
376 32, 1,
377 &m_deleteWindowProtocol);
378
379 m_outputs << output;
380 Q_EMIT outputAdded(output);
381 output->updateEnabled(true);
382 }
383
384 updateWindowTitle();
385
386 xcb_flush(m_connection);
387}
388
389#if HAVE_X11_XINPUT
390
391static inline qreal fixed1616ToReal(FP1616 val)
392{
393 return (val)*1.0 / (1 << 16);
394}
395#endif
396
397void X11WindowedBackend::handleEvent(xcb_generic_event_t *e)
398{
399 const uint8_t eventType = e->response_type & ~0x80;
400 switch (eventType) {
401 case XCB_BUTTON_PRESS:
402 case XCB_BUTTON_RELEASE:
403 handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(e));
404 break;
405 case XCB_MOTION_NOTIFY: {
406 auto event = reinterpret_cast<xcb_motion_notify_event_t *>(e);
407 const X11WindowedOutput *output = findOutput(event->event);
408 if (!output) {
409 break;
410 }
411 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y));
412 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get());
413 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
414 } break;
415 case XCB_KEY_PRESS:
416 case XCB_KEY_RELEASE: {
417 auto event = reinterpret_cast<xcb_key_press_event_t *>(e);
418 if (eventType == XCB_KEY_PRESS) {
419 if (!m_keySymbols) {
420 m_keySymbols = xcb_key_symbols_alloc(m_connection);
421 }
422 const xcb_keysym_t kc = xcb_key_symbols_get_keysym(m_keySymbols, event->detail, 0);
423 if (kc == XK_Control_R) {
424 grabKeyboard(event->time);
425 }
426 Q_EMIT m_keyboardDevice->keyChanged(event->detail - 8,
428 std::chrono::milliseconds(event->time),
429 m_keyboardDevice.get());
430 } else {
431 Q_EMIT m_keyboardDevice->keyChanged(event->detail - 8,
433 std::chrono::milliseconds(event->time),
434 m_keyboardDevice.get());
435 }
436 } break;
437 case XCB_CONFIGURE_NOTIFY:
438 updateSize(reinterpret_cast<xcb_configure_notify_event_t *>(e));
439 break;
440 case XCB_ENTER_NOTIFY: {
441 auto event = reinterpret_cast<xcb_enter_notify_event_t *>(e);
442 const X11WindowedOutput *output = findOutput(event->event);
443 if (!output) {
444 break;
445 }
446 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y));
447 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get());
448 } break;
449 case XCB_CLIENT_MESSAGE:
450 handleClientMessage(reinterpret_cast<xcb_client_message_event_t *>(e));
451 break;
452 case XCB_EXPOSE:
453 handleExpose(reinterpret_cast<xcb_expose_event_t *>(e));
454 break;
455 case XCB_MAPPING_NOTIFY:
456 if (m_keySymbols) {
457 xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast<xcb_mapping_notify_event_t *>(e));
458 }
459 break;
460 case XCB_GE_GENERIC: {
461 xcb_ge_generic_event_t *ev = reinterpret_cast<xcb_ge_generic_event_t *>(e);
462 if (ev->extension == m_presentOpcode) {
463 handlePresentEvent(ev);
464 } else if (ev->extension == m_xiOpcode) {
465 handleXinputEvent(ev);
466 }
467 break;
468 }
469 default:
470 break;
471 }
472}
473
474void X11WindowedBackend::grabKeyboard(xcb_timestamp_t time)
475{
476 const bool oldState = m_keyboardGrabbed;
477 if (m_keyboardGrabbed) {
478 xcb_ungrab_keyboard(m_connection, time);
479 xcb_ungrab_pointer(m_connection, time);
480 m_keyboardGrabbed = false;
481 } else {
482 const X11WindowedOutput *output = static_cast<X11WindowedOutput *>(m_outputs[0]);
483 const auto c = xcb_grab_keyboard_unchecked(m_connection, false, output->window(), time,
484 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
485 UniqueCPtr<xcb_grab_keyboard_reply_t> grab(xcb_grab_keyboard_reply(m_connection, c, nullptr));
486 if (!grab) {
487 return;
488 }
489 if (grab->status == XCB_GRAB_STATUS_SUCCESS) {
490 const auto c = xcb_grab_pointer_unchecked(m_connection, false, output->window(),
491 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,
492 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
493 output->window(), XCB_CURSOR_NONE, time);
494 UniqueCPtr<xcb_grab_pointer_reply_t> grab(xcb_grab_pointer_reply(m_connection, c, nullptr));
495 if (!grab || grab->status != XCB_GRAB_STATUS_SUCCESS) {
496 xcb_ungrab_keyboard(m_connection, time);
497 return;
498 }
499 m_keyboardGrabbed = true;
500 }
501 }
502 if (oldState != m_keyboardGrabbed) {
503 updateWindowTitle();
504 xcb_flush(m_connection);
505 }
506}
507
508void X11WindowedBackend::updateWindowTitle()
509{
510 const QString grab = m_keyboardGrabbed ? i18n("Press right control to ungrab input") : i18n("Press right control key to grab input");
511 const QString title = QStringLiteral("%1 - %2").arg(i18n("KDE Wayland Compositor"), grab);
512 for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
513 (*it)->setWindowTitle(title);
514 }
515}
516
517void X11WindowedBackend::handleClientMessage(xcb_client_message_event_t *event)
518{
519 auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
520 [event](X11WindowedOutput *output) {
521 return output->window() == event->window;
522 });
523 if (it == m_outputs.end()) {
524 return;
525 }
526 if (event->type == m_protocols && m_protocols != XCB_ATOM_NONE) {
527 if (event->data.data32[0] == m_deleteWindowProtocol && m_deleteWindowProtocol != XCB_ATOM_NONE) {
528 if (m_outputs.count() == 1) {
529 qCDebug(KWIN_X11WINDOWED) << "Backend window is going to be closed, shutting down.";
530 QCoreApplication::quit();
531 } else {
532 // remove the window
533 qCDebug(KWIN_X11WINDOWED) << "Removing one output window.";
534
535 auto removedOutput = *it;
536 it = m_outputs.erase(it);
537
538 removedOutput->updateEnabled(false);
539 Q_EMIT outputRemoved(removedOutput);
540 removedOutput->unref();
541 Q_EMIT outputsQueried();
542 }
543 }
544 }
545}
546
547void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event)
548{
549 const X11WindowedOutput *output = findOutput(event->event);
550 if (!output) {
551 return;
552 }
553 bool const pressed = (event->response_type & ~0x80) == XCB_BUTTON_PRESS;
554 if (event->detail >= XCB_BUTTON_INDEX_4 && event->detail <= 7) {
555 // wheel
556 if (!pressed) {
557 return;
558 }
559 const int delta = (event->detail == XCB_BUTTON_INDEX_4 || event->detail == 6) ? -120 : 120;
560 static const qreal s_defaultAxisStepDistance = 10.0;
562 if (event->detail > 5) {
564 } else {
566 }
567 Q_EMIT m_pointerDevice->pointerAxisChanged(axis,
568 delta * s_defaultAxisStepDistance,
569 delta,
571 std::chrono::milliseconds(event->time),
572 m_pointerDevice.get());
573 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
574 return;
575 }
576 uint32_t button = 0;
577 switch (event->detail) {
578 case XCB_BUTTON_INDEX_1:
579 button = BTN_LEFT;
580 break;
581 case XCB_BUTTON_INDEX_2:
582 button = BTN_MIDDLE;
583 break;
584 case XCB_BUTTON_INDEX_3:
585 button = BTN_RIGHT;
586 break;
587 default:
588 button = event->detail + BTN_LEFT - 1;
589 return;
590 }
591
592 const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y));
593 Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get());
594
595 if (pressed) {
596 Q_EMIT m_pointerDevice->pointerButtonChanged(button, InputRedirection::PointerButtonPressed, std::chrono::milliseconds(event->time), m_pointerDevice.get());
597 } else {
598 Q_EMIT m_pointerDevice->pointerButtonChanged(button, InputRedirection::PointerButtonReleased, std::chrono::milliseconds(event->time), m_pointerDevice.get());
599 }
600 Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
601}
602
603void X11WindowedBackend::handleExpose(xcb_expose_event_t *event)
604{
605 X11WindowedOutput *output = findOutput(event->window);
606 if (output) {
607 output->addExposedArea(QRect(event->x, event->y, event->width, event->height));
608 output->renderLoop()->scheduleRepaint();
609 }
610}
611
612void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event)
613{
614 X11WindowedOutput *output = findOutput(event->window);
615 if (!output) {
616 return;
617 }
618
619 output->setHostPosition(QPoint(event->x, event->y));
620
621 const QSize s = QSize(event->width, event->height);
622 if (s != output->pixelSize()) {
623 output->resize(s);
624 }
625}
626
627void X11WindowedBackend::handleXinputEvent(xcb_ge_generic_event_t *ge)
628{
629#if HAVE_X11_XINPUT
630 auto te = reinterpret_cast<xXIDeviceEvent *>(ge);
631 const X11WindowedOutput *output = findOutput(te->event);
632 if (!output) {
633 return;
634 }
635
636 const QPointF position = output->mapFromGlobal(QPointF(fixed1616ToReal(te->root_x), fixed1616ToReal(te->root_y)));
637
638 switch (ge->event_type) {
639 case XI_TouchBegin: {
640 Q_EMIT m_touchDevice->touchDown(te->detail, position, std::chrono::milliseconds(te->time), m_touchDevice.get());
641 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get());
642 break;
643 }
644 case XI_TouchUpdate: {
645 Q_EMIT m_touchDevice->touchMotion(te->detail, position, std::chrono::milliseconds(te->time), m_touchDevice.get());
646 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get());
647 break;
648 }
649 case XI_TouchEnd: {
650 Q_EMIT m_touchDevice->touchUp(te->detail, std::chrono::milliseconds(te->time), m_touchDevice.get());
651 Q_EMIT m_touchDevice->touchFrame(m_touchDevice.get());
652 break;
653 }
654 case XI_TouchOwnership: {
655 auto te = reinterpret_cast<xXITouchOwnershipEvent *>(ge);
656 XIAllowTouchEvents(m_display, te->deviceid, te->sourceid, te->touchid, XIAcceptTouch);
657 break;
658 }
659 }
660#endif
661}
662
663void X11WindowedBackend::handlePresentEvent(xcb_ge_generic_event_t *ge)
664{
665 switch (ge->event_type) {
666 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
667 xcb_present_idle_notify_event_t *idleNotify = reinterpret_cast<xcb_present_idle_notify_event_t *>(ge);
668 if (X11WindowedOutput *output = findOutput(idleNotify->window)) {
669 output->handlePresentIdleNotify(idleNotify);
670 }
671 break;
672 }
673 case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
674 xcb_present_complete_notify_event_t *completeNotify = reinterpret_cast<xcb_present_complete_notify_event_t *>(ge);
675 if (X11WindowedOutput *output = findOutput(completeNotify->window)) {
676 output->handlePresentCompleteNotify(completeNotify);
677 }
678 break;
679 }
680 }
681}
682
684{
685 if (!m_screen) {
686 return XCB_WINDOW_NONE;
687 }
688 return m_screen->root;
689}
690
692{
693 return m_gbmDevice;
694}
695
697{
698 return m_pointerDevice.get();
699}
700
702{
703 return m_keyboardDevice.get();
704}
705
707{
708 return m_touchDevice.get();
709}
710
711std::unique_ptr<OpenGLBackend> X11WindowedBackend::createOpenGLBackend()
712{
713 return std::make_unique<X11WindowedEglBackend>(this);
714}
715
716std::unique_ptr<QPainterBackend> X11WindowedBackend::createQPainterBackend()
717{
718 return std::make_unique<X11WindowedQPainterBackend>(this);
719}
720
721std::unique_ptr<InputBackend> X11WindowedBackend::createInputBackend()
722{
723 return std::make_unique<X11WindowedInputBackend>(this);
724}
725
726xcb_connection_t *X11WindowedBackend::connection() const
727{
728 return m_connection;
729}
730
731xcb_screen_t *X11WindowedBackend::screen() const
732{
733 return m_screen;
734}
735
737{
738 return m_screenNumber;
739}
740
742{
743 return m_display;
744}
745
747{
748 return m_hasXInput;
749}
750
751QHash<uint32_t, QList<uint64_t>> X11WindowedBackend::driFormats() const
752{
753 return m_driFormats;
754}
755
757{
758 switch (depth) {
759 case 24:
760 return DRM_FORMAT_XRGB8888;
761 case 32:
762 return DRM_FORMAT_ARGB8888;
763 default:
764 return 0;
765 }
766}
767
769{
770 return m_driMajorVersion;
771}
772
774{
775 return m_driMinorVersion;
776}
777
778QList<CompositingType> X11WindowedBackend::supportedCompositors() const
779{
780 QList<CompositingType> ret;
781 if (m_gbmDevice) {
782 ret.append(OpenGLCompositing);
783 }
784 if (m_hasShm) {
785 ret.append(QPainterCompositing);
786 }
787 return ret;
788}
789
791{
792 return m_outputs;
793}
794
795void X11WindowedBackend::destroyOutputs()
796{
797 while (!m_outputs.isEmpty()) {
798 auto output = m_outputs.takeLast();
799 output->updateEnabled(false);
800 Q_EMIT outputRemoved(output);
801 delete output;
802 }
803}
804
805void X11WindowedBackend::setEglDisplay(std::unique_ptr<EglDisplay> &&display)
806{
807 m_eglDisplay = std::move(display);
808}
809
811{
812 return m_eglDisplay.get();
813}
814
815} // namespace KWin
816
817#include "moc_x11_windowed_backend.cpp"
void deviceAdded(InputDevice *device)
void outputAdded(Output *output)
void outputRemoved(Output *output)
X11WindowedInputDevice * pointerDevice() const
void setEglDisplay(std::unique_ptr< EglDisplay > &&display)
std::unique_ptr< OpenGLBackend > createOpenGLBackend() override
X11WindowedInputDevice * touchDevice() const
xcb_connection_t * connection() const
std::unique_ptr< InputBackend > createInputBackend() override
X11WindowedBackend(const X11WindowedBackendOptions &options)
EglDisplay * sceneEglDisplayObject() const override
uint32_t driFormatForDepth(int depth) const
QHash< uint32_t, QList< uint64_t > > driFormats() const
X11WindowedInputDevice * keyboardDevice() const
Outputs outputs() const override
std::unique_ptr< QPainterBackend > createQPainterBackend() override
QList< CompositingType > supportedCompositors() const override
xcb_screen_t * screen() const
X11WindowedInputBackend(X11WindowedBackend *backend)
void setEnabled(bool enabled) override
void setLeds(LEDs leds) override
bool isTabletModeSwitch() const override
QString sysName() const override
void setName(const QString &name)
#define XCB_GE_GENERIC
Definition events.cpp:57
void init(xcb_connection_t *connection, xcb_window_t rootWindow)
GLenum format
Definition gltexture.cpp:49
@ QPainterCompositing
Definition globals.h:39
@ OpenGLCompositing
Definition globals.h:37
Options * options
Definition main.cpp:73
std::unique_ptr< T, CDeleter > UniqueCPtr
Definition c_ptr.h:28
struct _XDisplay Display