4#include <QtGui/private/qguiapplication_p.h>
5#include <QtCore/QDebug>
6#include <QtCore/QCoreApplication>
12#if QT_CONFIG(draganddrop)
25#include <QAbstractEventDispatcher>
27#include <QScopedPointer>
32#include <xcb/xfixes.h>
33#define explicit dont_use_cxx_explicit
36#include <xcb/xinput.h>
38#if QT_CONFIG(xcb_xlib)
59 , m_duringSystemMoveResize(
false)
60 , m_canGrabServer(canGrabServer)
61 , m_defaultVisualId(defaultVisualId)
62 , m_nativeInterface(nativeInterface)
72 initializeScreens(
false);
76 xi2SelectStateEvents();
81#ifndef QT_NO_CLIPBOARD
84#if QT_CONFIG(draganddrop)
88 setStartupId(
qgetenv(
"DESKTOP_STARTUP_ID"));
89 if (!startupId().isNull())
92 const int focusInDelay = 100;
93 m_focusInTimer.setSingleShot(
true);
94 m_focusInTimer.setInterval(focusInDelay);
95 m_focusInTimer.callOnTimeout(
this, []() {
105#ifndef QT_NO_CLIPBOARD
108#if QT_CONFIG(draganddrop)
118 while (!m_virtualDesktops.
isEmpty())
119 delete m_virtualDesktops.
takeLast();
121 delete m_glIntegration;
130 return m_screens.
first();
138 m_mapper.
insert(
id, eventListener);
148 return m_mapper.
value(
id,
nullptr);
159#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
161 auto e = reinterpret_cast<event_t *>(event); \
162 if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \
163 if (eventListener->handleNativeEvent(event)) \
165 eventListener->handler(e); \
170#define HANDLE_KEYBOARD_EVENT(event_t, handler) \
172 auto e = reinterpret_cast<event_t *>(event); \
173 if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \
174 if (eventListener->handleNativeEvent(event)) \
176 m_keyboard->handler(e); \
182 xcb_generic_event_t *
event)
const
184 quint8 response_type =
event->response_type & ~0x80;
185 quint16 sequence =
event->sequence;
187#define PRINT_AND_RETURN(name) { \
188 qCDebug(log, "%s | %s(%d) | sequence: %d", message, name, response_type, sequence); \
191#define CASE_PRINT_AND_RETURN(name) case name : PRINT_AND_RETURN(#name);
193#define XI_PRINT_AND_RETURN(name) { \
194 qCDebug(log, "%s | XInput Event(%s) | sequence: %d", message, name, sequence); \
197#define XI_CASE_PRINT_AND_RETURN(name) case name : XI_PRINT_AND_RETURN(#name);
199 switch (response_type) {
233 case XCB_GE_GENERIC: {
235 auto *xiDeviceEvent =
reinterpret_cast<const xcb_input_button_press_event_t*
>(
event);
236 switch (xiDeviceEvent->event_type) {
263 qCDebug(log,
"%s | XInput Event(other type) | sequence: %d",
message, sequence);
267 qCDebug(log,
"%s | %s(%d) | sequence: %d",
message,
"XCB_GE_GENERIC", response_type, sequence);
273 if (
isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY))
279 if (
isXRandrType(response_type, XCB_RANDR_SCREEN_CHANGE_NOTIFY))
287 qCDebug(log,
"%s | unknown(%d) | sequence: %d",
message, response_type, sequence);
289#undef PRINT_AND_RETURN
290#undef CASE_PRINT_AND_RETURN
320 "ChangeWindowAttributes",
321 "GetWindowAttributes",
348 "ChangeActivePointerGrab",
398 "CopyColormapAndFree",
401 "ListInstalledColormaps",
418 "ChangeKeyboardMapping",
419 "GetKeyboardMapping",
420 "ChangeKeyboardControl",
421 "GetKeyboardControl",
423 "ChangePointerControl",
436 "SetModifierMapping",
437 "GetModifierMapping",
456 qCDebug(lcQpaXcb,
"%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
459 int(
error->sequence),
int(
error->resource_id),
461 int(
error->minor_code));
466 Qt::MouseButtons
ret;
467 if (
s & XCB_BUTTON_MASK_1)
469 if (
s & XCB_BUTTON_MASK_2)
471 if (
s & XCB_BUTTON_MASK_3)
478 m_buttonState.setFlag(
button, down);
521 uint8_t response_type;
524 xcb_timestamp_t
time;
527 xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
528 xcb_xkb_map_notify_event_t map_notify;
529 xcb_xkb_state_notify_event_t state_notify;
535 if (
Q_UNLIKELY(lcQpaEvents().isDebugEnabled()))
544 uint response_type =
event->response_type & ~0x80;
547 switch (response_type) {
550 case XCB_BUTTON_PRESS: {
551 auto ev =
reinterpret_cast<xcb_button_press_event_t *
>(
event);
558 if (
Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
559 qCDebug(lcQpaXInputEvents,
"legacy mouse press, button %d state %X",
560 ev->detail,
static_cast<unsigned int>(m_buttonState));
563 case XCB_BUTTON_RELEASE: {
564 auto ev =
reinterpret_cast<xcb_button_release_event_t *
>(
event);
566 if (m_duringSystemMoveResize && ev->root != XCB_NONE)
571 if (
Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
572 qCDebug(lcQpaXInputEvents,
"legacy mouse release, button %d state %X",
573 ev->detail,
static_cast<unsigned int>(m_buttonState));
576 case XCB_MOTION_NOTIFY: {
577 auto ev =
reinterpret_cast<xcb_motion_notify_event_t *
>(
event);
581 if (
Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
582 qCDebug(lcQpaXInputEvents,
"legacy mouse move %d,%d button %d state %X",
583 ev->event_x, ev->event_y, ev->detail,
static_cast<unsigned int>(m_buttonState));
586 case XCB_CONFIGURE_NOTIFY: {
588 auto ev =
reinterpret_cast<xcb_configure_notify_event_t *
>(
event);
590 initializeScreens(
true);
596 case XCB_UNMAP_NOTIFY:
598 case XCB_DESTROY_NOTIFY:
600 case XCB_CLIENT_MESSAGE: {
601 auto clientMessage =
reinterpret_cast<xcb_client_message_event_t *
>(
event);
602 if (clientMessage->format != 32)
604#if QT_CONFIG(draganddrop)
606 drag()->handleStatus(clientMessage);
608 drag()->handleFinished(clientMessage);
614 case XCB_ENTER_NOTIFY:
621 case XCB_LEAVE_NOTIFY:
627 auto ev =
reinterpret_cast<xcb_leave_notify_event_t *
>(
event);
638 auto keyPress =
reinterpret_cast<xcb_key_press_event_t *
>(
event);
644 case XCB_KEY_RELEASE:
646 auto keyRelease =
reinterpret_cast<xcb_key_release_event_t *
>(
event);
651 case XCB_MAPPING_NOTIFY:
654 case XCB_SELECTION_REQUEST:
656#if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard)
657 auto selectionRequest =
reinterpret_cast<xcb_selection_request_event_t *
>(
event);
658 setTime(selectionRequest->time);
660#if QT_CONFIG(draganddrop)
662 m_drag->handleSelectionRequest(selectionRequest);
666#ifndef QT_NO_CLIPBOARD
672 case XCB_SELECTION_CLEAR:
674#ifndef QT_NO_CLIPBOARD
678 case XCB_SELECTION_NOTIFY:
681 case XCB_PROPERTY_NOTIFY:
683 auto propertyNotify =
reinterpret_cast<xcb_property_notify_event_t *
>(
event);
685#ifndef QT_NO_CLIPBOARD
690 QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
694 m_wmSupport->updateNetWMAtoms();
703 xi2HandleEvent(
reinterpret_cast<xcb_ge_event_t *
>(
event));
714 if (
isXFixesType(response_type, XCB_XFIXES_SELECTION_NOTIFY)) {
715 auto notify_event =
reinterpret_cast<xcb_xfixes_selection_notify_event_t *
>(
event);
716 setTime(notify_event->timestamp);
717#ifndef QT_NO_CLIPBOARD
721 virtualDesktop->handleXFixesSelectionNotify(notify_event);
722 }
else if (
isXRandrType(response_type, XCB_RANDR_NOTIFY)) {
724 updateScreens(
reinterpret_cast<xcb_randr_notify_event_t *
>(
event));
725 }
else if (
isXRandrType(response_type, XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
727 auto change_event =
reinterpret_cast<xcb_randr_screen_change_notify_event_t *
>(
event);
728 if (
auto virtualDesktop = virtualDesktopForRootWindow(change_event->root))
729 virtualDesktop->handleScreenChange(change_event);
732 auto xkb_event =
reinterpret_cast<_xkb_event *
>(
event);
733 if (xkb_event->any.deviceID == m_keyboard->
coreDeviceId()) {
734 switch (xkb_event->any.xkbType) {
737 case XCB_XKB_STATE_NOTIFY:
740 case XCB_XKB_MAP_NOTIFY:
743 case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
744 xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify;
745 if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
766 m_focusWindow =
w ?
static_cast<QXcbWindow *
>(
w->handle()) :
nullptr;
771 m_mousePressWindow =
nullptr;
775 m_mousePressWindow =
w;
785 if (m_clientLeader) {
788 XCB_PROP_MODE_REPLACE,
827 XCB_ATOM_INTEGER, 32, 0,
nullptr);
831 xcb_generic_event_t *
event =
nullptr;
839 if (
type != XCB_PROPERTY_NOTIFY)
841 auto propertyNotify =
reinterpret_cast<xcb_property_notify_event_t *
>(
event);
842 return propertyNotify->window ==
window && propertyNotify->atom == dummyAtom;
851 return XCB_CURRENT_TIME;
854 xcb_property_notify_event_t *pn =
reinterpret_cast<xcb_property_notify_event_t *
>(
event);
855 xcb_timestamp_t timestamp = pn->time;
865 qCDebug(lcQpaXcb) <<
"failed to query selection owner";
874 if (!m_qtSelectionOwner) {
876 int16_t
x = 0,
y = 0;
877 uint16_t
w = 3,
h = 3;
880 XCB_COPY_FROM_PARENT,
885 XCB_WINDOW_CLASS_INPUT_OUTPUT,
886 xcbScreen->root_visual,
893 return m_qtSelectionOwner;
899 return s ?
s->root() : 0;
904 if (m_clientLeader == 0) {
908 XCB_COPY_FROM_PARENT,
913 XCB_WINDOW_CLASS_INPUT_OUTPUT,
914 screen->screen()->root_visual,
922 XCB_PROP_MODE_REPLACE,
935 XCB_PROP_MODE_REPLACE,
947 return m_clientLeader;
962bool QXcbConnection::compressEvent(xcb_generic_event_t *
event)
const
967 uint responseType =
event->response_type & ~0x80;
969 if (responseType == XCB_MOTION_NOTIFY) {
972 [](xcb_generic_event_t *,
int type) {
973 return type == XCB_MOTION_NOTIFY;
978 if (responseType == XCB_GE_GENERIC) {
984#if QT_CONFIG(tabletevent)
985 auto xdev =
reinterpret_cast<xcb_input_motion_event_t *
>(
event);
987 const_cast<QXcbConnection *
>(
this)->tabletDataForDevice(xdev->sourceid))
991 [
this](xcb_generic_event_t *
next,
int) {
998 auto touchUpdateEvent =
reinterpret_cast<xcb_input_touch_update_event_t *
>(
event);
999 uint32_t
id = touchUpdateEvent->detail % INT_MAX;
1002 [
this, &
id](xcb_generic_event_t *
next,
int) {
1005 auto touchUpdateNextEvent =
reinterpret_cast<xcb_input_touch_update_event_t *
>(
next);
1006 return id == touchUpdateNextEvent->detail % INT_MAX;
1013 if (responseType == XCB_CONFIGURE_NOTIFY) {
1017 if (
type != XCB_CONFIGURE_NOTIFY)
1019 auto currentEvent =
reinterpret_cast<xcb_configure_notify_event_t *
>(
event);
1020 auto nextEvent =
reinterpret_cast<xcb_configure_notify_event_t *
>(
next);
1021 return currentEvent->event == nextEvent->event;
1030 auto eventType =
event->response_type & ~0x80;
1031 bool isInputEvent = eventType == XCB_BUTTON_PRESS ||
1032 eventType == XCB_BUTTON_RELEASE ||
1033 eventType == XCB_KEY_PRESS ||
1034 eventType == XCB_KEY_RELEASE ||
1035 eventType == XCB_MOTION_NOTIFY ||
1036 eventType == XCB_ENTER_NOTIFY ||
1037 eventType == XCB_LEAVE_NOTIFY;
1056 if (eventType == XCB_CLIENT_MESSAGE) {
1057 auto clientMessage =
reinterpret_cast<const xcb_client_message_event_t *
>(
event);
1060 isInputEvent =
true;
1063 return isInputEvent;
1068 int connection_error = xcb_connection_has_error(
xcb_connection());
1069 if (connection_error) {
1070 qWarning(
"The X11 connection broke (error %d). Did the X11 server die?", connection_error);
1077 QScopedPointer<xcb_generic_event_t, QScopedPointerPodDeleter> eventGuard(
event);
1079 if (!(
event->response_type & ~0x80)) {
1084 if (compressEvent(
event))
1095#if QT_CONFIG(xcb_xlib)
1096 qt_XFlush(
static_cast<Display *
>(xlib_display()));
1104 xcb_format_iterator_t iterator =
1105 xcb_setup_pixmap_formats_iterator(
setup());
1107 while (iterator.rem) {
1108 xcb_format_t *
format = iterator.data;
1111 xcb_format_next(&iterator);
1114 qWarning() <<
"XCB failed to find an xcb_format_t for depth:" <<
depth;
1121 xcb_get_input_focus_cookie_t cookie = xcb_get_input_focus(
xcb_connection());
1122 free(xcb_get_input_focus_reply(
xcb_connection(), cookie,
nullptr));
1127 if (!m_systemTrayTracker) {
1134 return m_systemTrayTracker;
1146 if (m_glIntegrationInitialized)
1147 return m_glIntegration;
1152 if (!glIntegrationName.isEmpty()) {
1153 qCDebug(lcQpaGl) <<
"QT_XCB_GL_INTEGRATION is set to" << glIntegrationName;
1154 if (glIntegrationName !=
"none"_L1) {
1155 glIntegrationNames.removeAll(glIntegrationName);
1156 glIntegrationNames.prepend(glIntegrationName);
1158 glIntegrationNames.clear();
1162 if (!glIntegrationNames.isEmpty()) {
1163 qCDebug(lcQpaGl) <<
"Choosing xcb gl-integration based on following priority\n" << glIntegrationNames;
1164 for (
int i = 0;
i < glIntegrationNames.size() && !m_glIntegration;
i++) {
1167 qCDebug(lcQpaGl) <<
"Failed to initialize xcb gl-integration" << glIntegrationNames.at(
i);
1168 delete m_glIntegration;
1169 m_glIntegration =
nullptr;
1172 if (!m_glIntegration)
1173 qCDebug(lcQpaGl) <<
"Failed to create xcb gl-integration";
1176 m_glIntegrationInitialized =
true;
1177 return m_glIntegration;
1186 w->updateSyncRequestCounter();
1218 m_connection =
nullptr;
1224#include "moc_qxcbconnection.cpp"
static QAbstractEventDispatcher * instance(QThread *thread=nullptr)
Returns a pointer to the event dispatcher object for the specified thread.
bool filterNativeEvent(const QByteArray &eventType, void *message, qintptr *result)
Sends message through the event filters that were set by installNativeEventFilter().
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
QString applicationName
the name of this application
Type type() const
Returns the event type.
static QPlatformNativeInterface * platformNativeInterface()
QString applicationDisplayName
the user-visible name of this application
bool remove(const Key &key)
Removes the item that has the key from the hash.
T value(const Key &key) const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
bool isEmpty() const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
The QScreen class is used to query screen properties. \inmodule QtGui.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString toLower() const &
static void handleFocusWindowChanged(QWindow *window, Qt::FocusReason r=Qt::OtherFocusReason)
static void handleScreenRemoved(QPlatformScreen *screen)
Should be called by the implementation whenever a screen is removed.
bool isXIEvent(xcb_generic_event_t *event) const
bool isAtLeastXRandR15() const
int primaryScreenNumber() const
xcb_connection_t * xcb_connection() const
const xcb_setup_t * setup() const
bool isXRandrType(uint responseType, int eventType) const
bool isXkbType(uint responseType) const
bool isXIType(xcb_generic_event_t *event, uint16_t type) const
xcb_atom_t atom(QXcbAtom::Atom qatom) const
bool isXFixesType(uint responseType, int eventType) const
void handleSelectionClearRequest(xcb_selection_clear_event_t *event)
bool handlePropertyNotify(const xcb_generic_event_t *event)
void handleSelectionRequest(xcb_selection_request_event_t *event)
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event)
Q_NODISCARD_CTOR QXcbConnectionGrabber(QXcbConnection *connection)
xcb_window_t selectionOwner(xcb_atom_t atom) const
xcb_window_t rootWindow()
bool isUserInputEvent(xcb_generic_event_t *event) const
void setMousePressWindow(QXcbWindow *)
Qt::MouseButton translateMouseButton(xcb_button_t s)
void printXcbEvent(const QLoggingCategory &log, const char *message, xcb_generic_event_t *event) const
QXcbGlIntegration * glIntegration() const
void setMouseGrabber(QXcbWindow *)
void setTime(xcb_timestamp_t t)
void setButtonState(Qt::MouseButton button, bool down)
QString windowManagerName() const
QXcbConnection * connection() const
void processXcbEvents(QEventLoop::ProcessEventsFlags flags)
void printXcbError(const char *message, xcb_generic_error_t *error)
xcb_timestamp_t time() const
QXcbScreen * primaryScreen() const
bool event(QEvent *e) override
This virtual function receives events to an object and should return true if the event e was recogniz...
xcb_window_t qtSelectionOwner()
void handleXcbError(xcb_generic_error_t *error)
QXcbVirtualDesktop * primaryVirtualDesktop() const
void setFocusWindow(QWindow *)
Qt::MouseButtons queryMouseButtons() const
void abortSystemMoveResize(xcb_window_t window)
QXcbEventQueue * eventQueue() const
xcb_window_t clientLeader()
void setStartupId(const QByteArray &nextId)
QXcbWindowEventListener * windowEventListenerFromId(xcb_window_t id)
Qt::MouseButton button() const
QByteArray startupId() const
const xcb_format_t * formatForDepth(uint8_t depth) const
QXcbWindow * platformWindowFromId(xcb_window_t id)
void addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener)
xcb_timestamp_t getTimestamp()
void handleXcbEvent(xcb_generic_event_t *event)
QXcbSystemTrayTracker * systemTrayTracker() const
void removeWindowEventListener(xcb_window_t id)
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask=nullptr)
xcb_generic_event_t * takeFirst(QEventLoop::ProcessEventsFlags flags)
xcb_generic_event_t * peek(Peeker &&peeker)
void flushBufferedEvents()
static QXcbGlIntegration * create(const QString &name)
virtual bool initialize(QXcbConnection *connection)=0
virtual bool handleXcbEvent(xcb_generic_event_t *event, uint responseType)
void updateKeymap(xcb_mapping_notify_event_t *event)
void updateXKBState(xcb_xkb_state_notify_event_t *state)
void updateXKBStateFromCore(quint16 state)
const QByteArray & nativeEventType() const
static QXcbSystemTrayTracker * create(QXcbConnection *connection)
void notifyManagerClientMessageEvent(const xcb_client_message_event_t *)
QString windowManagerName() const
xcb_screen_t * screen() const
virtual QXcbWindow * toWindow()
void clearSyncWindowRequest()
void setWindowTitle(const QString &title) override
Reimplement to set the window title to title.
Combined button and popup list for selecting options.
@ AA_CompressTabletEvents
@ AA_CompressHighFrequencyEvents
@ ActiveWindowFocusReason
static QString displayName(CGDirectDisplayID displayID)
DBusConnection const char DBusError * error
DBusConnection * connection
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLfloat GLfloat GLfloat w
[0]
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLenum GLenum GLenum input
#define QStringLiteral(str)
void qt_XFlush(Display *dpy)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qunsetenv(const char *varName)
#define HANDLE_KEYBOARD_EVENT(event_t, handler)
#define CASE_PRINT_AND_RETURN(name)
const char * xcb_protocol_request_codes[]
static Qt::MouseButtons translateMouseButtons(int s)
#define PRINT_AND_RETURN(name)
#define XI_CASE_PRINT_AND_RETURN(name)
#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler)
const char * xcb_errors[]
#define Q_XCB_REPLY(call,...)