diff options
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/main.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 33 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 15 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 288 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 30 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 47 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbnativeinterface.h | 13 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 1 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp | 180 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbsystemtraytracker.h | 87 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/xcb-plugin.pro | 6 |
14 files changed, 589 insertions, 136 deletions
diff --git a/src/plugins/platforms/xcb/main.cpp b/src/plugins/platforms/xcb/main.cpp index be5a0e3501..e114827703 100644 --- a/src/plugins/platforms/xcb/main.cpp +++ b/src/plugins/platforms/xcb/main.cpp @@ -47,15 +47,15 @@ QT_BEGIN_NAMESPACE class QXcbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "xcb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "xcb.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters) +QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { if (system.toLower() == "xcb") - return new QXcbIntegration(parameters); + return new QXcbIntegration(parameters, argc, argv); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 01af23377e..3f717ae2df 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -51,6 +51,7 @@ #include "qxcbwmsupport.h" #include "qxcbnativeinterface.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" #include <QtAlgorithms> #include <QSocketNotifier> @@ -262,6 +263,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , has_xkb(false) , m_buttons(0) , m_focusWindow(0) + , m_systemTrayTracker(0) { #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); @@ -656,6 +658,11 @@ void QXcbConnection::log(const char *file, int line, int sequence) void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { + long result = 0; + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); + if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) + return; + uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); @@ -813,6 +820,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); case XCB_UNMAP_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_DESTROY_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); case XCB_CLIENT_MESSAGE: handleClientMessageEvent((xcb_client_message_event_t *)event); break; @@ -1193,6 +1202,8 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t * drag()->handleFinished(event); } #endif + if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER)) + m_systemTrayTracker->notifyManagerClientMessageEvent(event); QXcbWindow *window = platformWindowFromId(event->window); if (!window) @@ -1228,6 +1239,8 @@ static const char * xcb_atomnames = { "_NET_WM_CONTEXT_HELP\0" "_NET_WM_SYNC_REQUEST\0" "_NET_WM_SYNC_REQUEST_COUNTER\0" + "MANAGER\0" + "_NET_SYSTEM_TRAY_OPCODE\0" // ICCCM window state "WM_STATE\0" @@ -1385,6 +1398,8 @@ static const char * xcb_atomnames = { "Abs MT Pressure\0" "Abs MT Tracking ID\0" "Max Contacts\0" + "Rel X\0" + "Rel Y\0" // XInput2 tablet "Abs X\0" "Abs Y\0" @@ -1401,11 +1416,16 @@ static const char * xcb_atomnames = { "_XSETTINGS_SETTINGS\0" // \0\0 terminates loop. }; -xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) +xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } +QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const +{ + return static_cast<QXcbAtom::Atom>(qFind(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms); +} + void QXcbConnection::initializeAllAtoms() { const char *names[QXcbAtom::NAtoms]; const char *ptr = xcb_atomnames; @@ -1721,6 +1741,17 @@ bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int o } #endif // defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) +QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() +{ + if (!m_systemTrayTracker) { + if ( (m_systemTrayTracker = QXcbSystemTrayTracker::create(this)) ) { + connect(m_systemTrayTracker, SIGNAL(systemTrayWindowChanged(QScreen*)), + QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*))); + } + } + return m_systemTrayTracker; +} + QXcbConnectionGrabber::QXcbConnectionGrabber(QXcbConnection *connection) :m_connection(connection) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 2a5ff0b1cb..aa0e070061 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -87,6 +87,7 @@ class QXcbKeyboard; class QXcbClipboard; class QXcbWMSupport; class QXcbNativeInterface; +class QXcbSystemTrayTracker; namespace QXcbAtom { enum Atom { @@ -98,6 +99,8 @@ namespace QXcbAtom { _NET_WM_CONTEXT_HELP, _NET_WM_SYNC_REQUEST, _NET_WM_SYNC_REQUEST_COUNTER, + MANAGER, // System tray notification + _NET_SYSTEM_TRAY_OPCODE, // System tray operation // ICCCM window state WM_STATE, @@ -256,6 +259,8 @@ namespace QXcbAtom { AbsMTPressure, AbsMTTrackingID, MaxContacts, + RelX, + RelY, // XInput2 tablet AbsX, AbsY, @@ -319,6 +324,7 @@ public: virtual void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *) {} virtual void handleMapNotifyEvent(const xcb_map_notify_event_t *) {} virtual void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *) {} + virtual void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) {} virtual void handleButtonPressEvent(const xcb_button_press_event_t *) {} virtual void handleButtonReleaseEvent(const xcb_button_release_event_t *) {} virtual void handleMotionNotifyEvent(const xcb_motion_notify_event_t *) {} @@ -346,7 +352,8 @@ public: const QList<QXcbScreen *> &screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } - xcb_atom_t atom(QXcbAtom::Atom atom); + xcb_atom_t atom(QXcbAtom::Atom atom) const; + QXcbAtom::Atom qatom(xcb_atom_t atom) const; xcb_atom_t internAtom(const char *name); QByteArray atomName(xcb_atom_t atom); @@ -430,6 +437,9 @@ public: void ungrabServer(); QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } + + QXcbSystemTrayTracker *systemTrayTracker(); + private slots: void processXcbEvents(); @@ -478,8 +488,6 @@ private: }; QHash<int, ValuatorClassInfo> valuatorInfo; }; - void xi2QueryTabletData(void *dev, TabletData *tabletData); // use no XI stuff in headers - void xi2SetupTabletDevices(); bool xi2HandleTabletEvent(void *event, TabletData *tabletData); void xi2ReportTabletEvent(const TabletData &tabletData, void *event); QVector<TabletData> m_tabletData; @@ -565,6 +573,7 @@ private: QXcbWindow *m_focusWindow; QByteArray m_startupId; + QXcbSystemTrayTracker *m_systemTrayTracker; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 991c82eaaa..466193b7a1 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -44,8 +44,8 @@ #include "qxcbwindow.h" #include "qtouchdevice.h" #include <qpa/qwindowsysteminterface.h> -//#define XI2_TOUCH_DEBUG -#ifdef XI2_TOUCH_DEBUG +//#define XI2_DEBUG +#ifdef XI2_DEBUG #include <QDebug> #endif @@ -63,20 +63,19 @@ struct XInput2DeviceData { } XIDeviceInfo *xiDeviceInfo; QTouchDevice *qtTouchDevice; -}; -#ifndef QT_NO_TABLETEVENT -static inline bool q_xi2_is_tablet(XIDeviceInfo *dev) -{ - QByteArray name(dev->name); - name = name.toLower(); - // Cannot just check for "wacom" because that would also pick up the touch and tablet-button devices. - return name.contains("stylus") || name.contains("eraser"); -} -#endif // QT_NO_TABLETEVENT + // Stuff that is relevant only for touchpads + QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed + QPointF firstPressedPosition; // in screen coordinates where the first point was pressed + QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed + QSizeF size; // device size in mm +}; void QXcbConnection::initializeXInput2() { +#ifndef QT_NO_TABLETEVENT + m_tabletData.clear(); +#endif Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; @@ -88,13 +87,76 @@ void QXcbConnection::initializeXInput2() m_xi2Enabled = true; } if (m_xi2Enabled) { +#ifdef XI2_DEBUG + qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); +#endif + int deviceCount = 0; + XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); + for (int i = 0; i < deviceCount; ++i) { + // Only non-master pointing devices are relevant here. + if (devices[i].use != XISlavePointer) + continue; +#ifdef XI2_DEBUG + qDebug() << "input device "<< devices[i].name; +#endif #ifndef QT_NO_TABLETEVENT - // Tablet support: Find the stylus-related devices. - xi2SetupTabletDevices(); + TabletData tabletData; +#endif + for (int c = 0; c < devices[i].num_classes; ++c) { + switch (devices[i].classes[c]->type) { + case XIValuatorClass: { + XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]); + const int valuatorAtom = qatom(vci->label); +#ifdef XI2_DEBUG + qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); +#endif +#ifndef QT_NO_TABLETEVENT + if (valuatorAtom < QXcbAtom::NAtoms) { + TabletData::ValuatorClassInfo info; + info.minVal = vci->min; + info.maxVal = vci->max; + info.number = vci->number; + tabletData.valuatorInfo[valuatorAtom] = info; + } #endif // QT_NO_TABLETEVENT -#ifdef XI2_TOUCH_DEBUG - qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); + } break; + default: + break; + } + } + bool isTablet = false; +#ifndef QT_NO_TABLETEVENT + // If we have found the valuators which we expect a tablet to have, assume it's a tablet. + if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) { + tabletData.deviceId = devices[i].deviceid; + tabletData.pointerType = QTabletEvent::Pen; + if (QByteArray(devices[i].name).toLower().contains("eraser")) + tabletData.pointerType = QTabletEvent::Eraser; + m_tabletData.append(tabletData); + isTablet = true; +#ifdef XI2_DEBUG + qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; #endif + } +#endif // QT_NO_TABLETEVENT +#ifdef XI2_DEBUG + if (!isTablet) { + XInput2DeviceData *dev = deviceForId(devices[i].deviceid); + if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) + qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints()); + else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints(), + dev->size.width(), dev->size.height()); + } +#endif // XI2_DEBUG + } + XIFreeDeviceInfo(devices); } } } @@ -113,25 +175,24 @@ void QXcbConnection::xi2Select(xcb_window_t window) unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask); #ifdef XCB_USE_XINPUT22 - // Select touch events on all master devices indiscriminately. bitMask |= XI_TouchBeginMask; bitMask |= XI_TouchUpdateMask; bitMask |= XI_TouchEndMask; XIEventMask mask; - mask.deviceid = XIAllMasterDevices; mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; - Status result = XISelectEvents(xDisplay, window, &mask, 1); - // If we have XInput 2.2 and successfully enable touch on the master - // devices, then evdev touchscreens will provide touch only. In most other - // cases, there will be emulated mouse events, because true X11 touch - // support is so new that for the older drivers, mouse emulation was the - // only way; and it's still the fallback even with the modern evdev driver. - // But if neither Qt nor X11 does mouse emulation, it will not be possible - // to interact with mouse-oriented QWidgets; so we have to let Qt do it. - if (m_xi2Minor >= 2 && result == Success) - has_touch_without_mouse_emulation = true; -#endif + // Enable each touchscreen + foreach (XInput2DeviceData *dev, m_touchDevices.values()) { + mask.deviceid = dev->xiDeviceInfo->deviceid; + Status result = XISelectEvents(xDisplay, window, &mask, 1); + // If we have XInput >= 2.2 and successfully enable a touchscreen, then + // it will provide touch only. In most other cases, there will be + // emulated mouse events from the driver. If not, then Qt must do its + // own mouse emulation to enable interaction with mouse-oriented QWidgets. + if (m_xi2Minor >= 2 && result == Success) + has_touch_without_mouse_emulation = true; + } +#endif // XCB_USE_XINPUT22 #ifndef QT_NO_TABLETEVENT // For each tablet, select some additional event types. @@ -163,23 +224,29 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) QTouchDevice::Capabilities caps = 0; dev = new XInput2DeviceData; dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &unused); - dev->qtTouchDevice = new QTouchDevice; + int type = -1; + int maxTouchPoints = 1; + bool hasRelativeCoords = false; for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; switch (classinfo->type) { #ifdef XCB_USE_XINPUT22 case XITouchClass: { XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); + maxTouchPoints = tci->num_touches; +#ifdef XI2_DEBUG + qDebug(" has touch class with mode %d", tci->mode); +#endif switch (tci->mode) { case XIModeRelative: - dev->qtTouchDevice->setType(QTouchDevice::TouchPad); + type = QTouchDevice::TouchPad; break; case XIModeAbsolute: - dev->qtTouchDevice->setType(QTouchDevice::TouchScreen); + type = QTouchDevice::TouchScreen; break; } } break; -#endif +#endif // XCB_USE_XINPUT22 case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); if (vci->label == atom(QXcbAtom::AbsMTPositionX)) @@ -188,18 +255,36 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) caps |= QTouchDevice::Area; else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) caps |= QTouchDevice::Pressure; + else if (vci->label == atom(QXcbAtom::RelX)) { + hasRelativeCoords = true; + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); + } else if (vci->label == atom(QXcbAtom::RelY)) { + hasRelativeCoords = true; + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + } } break; } } - dev->qtTouchDevice->setCapabilities(caps); - dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); - if (caps != 0) - QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); -#ifdef XI2_TOUCH_DEBUG - qDebug("registered new device %s with %d classes and %d max touch points", - dev->xiDeviceInfo->name, dev->xiDeviceInfo->num_classes, dev->qtTouchDevice->maxTouchPoints()); -#endif - m_touchDevices[id] = dev; + if (type < 0 && caps && hasRelativeCoords) { + type = QTouchDevice::TouchPad; + if (dev->size.width() < 10 || dev->size.height() < 10 || + dev->size.width() > 10000 || dev->size.height() > 10000) + dev->size = QSizeF(130, 110); + } + if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) { + dev->qtTouchDevice = new QTouchDevice; + dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); + dev->qtTouchDevice->setType((QTouchDevice::DeviceType)type); + dev->qtTouchDevice->setCapabilities(caps); + dev->qtTouchDevice->setMaximumTouchPoints(maxTouchPoints); + if (caps != 0) + QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); + m_touchDevices[id] = dev; + } else { + m_touchDevices.remove(id); + delete dev; + dev = 0; + } } return dev; } @@ -218,7 +303,7 @@ static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) value = vci->min; return (value - vci->min) / (vci->max - vci->min); } -#endif +#endif // XCB_USE_XINPUT22 void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { @@ -237,7 +322,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f", event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, xiDeviceEvent->event_x, xiDeviceEvent->event_y, @@ -247,6 +332,8 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { XInput2DeviceData *dev = deviceForId(xiEvent->deviceid); + Q_ASSERT(dev); + const bool firstTouch = m_touchPoints.isEmpty(); if (xiEvent->evtype == XI_TouchBegin) { QWindowSystemInterface::TouchPoint tp; tp.id = xiDeviceEvent->detail % INT_MAX; @@ -267,11 +354,15 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) continue; -#ifdef XI2_TOUCH_DEBUG - qDebug(" valuator class label %d value %lf from range %lf -> %lf name %s", - vci->label, value, vci->min, vci->max, XGetAtomName(static_cast<Display *>(m_xlib_display), vci->label) ); +#ifdef XI2_DEBUG + qDebug(" valuator %20s value %lf from range %lf -> %lf", + atomName(vci->label).constData(), value, vci->min, vci->max ); #endif - if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { + if (vci->label == atom(QXcbAtom::RelX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::RelY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { ny = valuatorNormalized(value, vci); @@ -306,19 +397,45 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } switch (xiEvent->evtype) { + case XI_TouchBegin: + if (firstTouch) { + dev->firstPressedPosition = QPointF(x, y); + dev->firstPressedNormalPosition = QPointF(nx, ny); + } + dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y)); + break; case XI_TouchUpdate: - if (touchPoint.area.center() != QPoint(x, y)) + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.height() * screen->geometry().height() / screen->physicalSize().height(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + touchPoint.state = Qt::TouchPointMoved; + } else if (touchPoint.area.center() != QPoint(x, y)) { touchPoint.state = Qt::TouchPointMoved; + dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + } else touchPoint.state = Qt::TouchPointStationary; break; case XI_TouchEnd: touchPoint.state = Qt::TouchPointReleased; + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + } + dev->pointPressedPosition.remove(touchPoint.id); } touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << " area " << touchPoint.area << " pressure " << touchPoint.pressure; #endif @@ -328,80 +445,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) m_touchPoints.remove(touchPoint.id); } } -#endif +#endif // XCB_USE_XINPUT22 } } #ifndef QT_NO_TABLETEVENT -void QXcbConnection::xi2QueryTabletData(void *dev, TabletData *tabletData) -{ - XIDeviceInfo *device = static_cast<XIDeviceInfo *>(dev); - tabletData->deviceId = device->deviceid; - - tabletData->pointerType = QTabletEvent::Pen; - if (QByteArray(device->name).toLower().contains("eraser")) - tabletData->pointerType = QTabletEvent::Eraser; - - for (int i = 0; i < device->num_classes; ++i) { - switch (device->classes[i]->type) { - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(device->classes[i]); - int val = 0; - if (vci->label == atom(QXcbAtom::AbsX)) - val = QXcbAtom::AbsX; - else if (vci->label == atom(QXcbAtom::AbsY)) - val = QXcbAtom::AbsY; - else if (vci->label == atom(QXcbAtom::AbsPressure)) - val = QXcbAtom::AbsPressure; - else if (vci->label == atom(QXcbAtom::AbsTiltX)) - val = QXcbAtom::AbsTiltX; - else if (vci->label == atom(QXcbAtom::AbsTiltY)) - val = QXcbAtom::AbsTiltY; - else if (vci->label == atom(QXcbAtom::AbsWheel)) - val = QXcbAtom::AbsWheel; - else if (vci->label == atom(QXcbAtom::AbsDistance)) - val = QXcbAtom::AbsDistance; - if (val) { - TabletData::ValuatorClassInfo info; - info.minVal = vci->min; - info.maxVal = vci->max; - info.number = vci->number; - tabletData->valuatorInfo[val] = info; - } - } - break; - default: - break; - } - } -} - -void QXcbConnection::xi2SetupTabletDevices() -{ - Display *xDisplay = static_cast<Display *>(m_xlib_display); - m_tabletData.clear(); - int deviceCount = 0; - XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); - if (devices) { - for (int i = 0; i < deviceCount; ++i) { - int unused = 0; - XIDeviceInfo *dev = XIQueryDevice(xDisplay, devices[i].deviceid, &unused); - if (dev) { - if (q_xi2_is_tablet(dev)) { - TabletData tabletData; - xi2QueryTabletData(dev, &tabletData); -#ifdef XI2_TOUCH_DEBUG - qDebug() << "found tablet" << dev->name; -#endif - m_tabletData.append(tabletData); - } - XIFreeDeviceInfo(dev); - } - } - XIFreeDeviceInfo(devices); - } -} - bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) { bool handled = true; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index cf7e99023a..68ad93143b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -119,9 +119,10 @@ static bool runningUnderDebugger() } #endif -QXcbIntegration::QXcbIntegration(const QStringList ¶meters) +QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_eventDispatcher(createUnixEventDispatcher()) , m_services(new QGenericUnixServices) + , m_instanceName(0) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); @@ -138,7 +139,28 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters) if (canNotGrabEnv) canGrab = false; - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab); + // Parse arguments + const char *displayName = 0; + if (argc) { + int j = 1; + for (int i = 1; i < argc; i++) { + char *arg = argv[i]; + if (arg) { + if (!strcmp(arg, "-display") && i < argc - 1) { + displayName = argv[++i]; + arg = 0; + } else if (!strcmp(arg, "-name") && i < argc - 1) { + m_instanceName = argv[++i]; + arg = 0; + } + } + if (arg) + argv[j++] = arg; + } + argc = j; + } // argc + + m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG @@ -365,6 +387,8 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::SynthesizeMouseFromTouchEvents: // We do not want Qt to synthesize mouse events if X11 already does it. return m_connections.at(0)->hasTouchWithoutMouseEmulation(); + default: + break; } return QPlatformIntegration::styleHint(hint); } @@ -389,6 +413,8 @@ QByteArray QXcbIntegration::wmClass() const if (m_wmClass.isEmpty()) { // Instance name according to ICCCM 4.1.2.5 QString name; + if (m_instanceName) + name = QString::fromLocal8Bit(m_instanceName); if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar)) name = QString::fromLocal8Bit(qgetenv(resourceNameVar)); if (name.isEmpty()) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 07b6b8d678..09fc0d32b5 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -55,7 +55,7 @@ class QXcbScreen; class QXcbIntegration : public QPlatformIntegration { public: - QXcbIntegration(const QStringList ¶meters); + QXcbIntegration(const QStringList ¶meters, int &argc, char **argv); ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const; @@ -119,6 +119,7 @@ private: friend class QXcbConnection; // access QPlatformIntegration::screenAdded() mutable QByteArray m_wmClass; + const char *m_instanceName; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index d1729ed168..2529fb8a83 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -243,6 +243,10 @@ #define XF86XK_Select 0x1008FFA0 #define XF86XK_View 0x1008FFA1 #define XF86XK_TopMenu 0x1008FFA2 +#define XF86XK_Red 0x1008FFA3 +#define XF86XK_Green 0x1008FFA4 +#define XF86XK_Yellow 0x1008FFA5 +#define XF86XK_Blue 0x1008FFA6 #define XF86XK_Suspend 0x1008FFA7 #define XF86XK_Hibernate 0x1008FFA8 #define XF86XK_TouchpadToggle 0x1008FFA9 @@ -538,6 +542,10 @@ static const unsigned int KeyTbl[] = { XF86XK_Select, Qt::Key_Select, XF86XK_View, Qt::Key_View, XF86XK_TopMenu, Qt::Key_TopMenu, + XF86XK_Red, Qt::Key_Red, + XF86XK_Green, Qt::Key_Green, + XF86XK_Yellow, Qt::Key_Yellow, + XF86XK_Blue, Qt::Key_Blue, XF86XK_Bluetooth, Qt::Key_Bluetooth, XF86XK_Suspend, Qt::Key_Suspend, XF86XK_Hibernate, Qt::Key_Hibernate, diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 9e9fd2914f..99e9932847 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -42,7 +42,9 @@ #include "qxcbnativeinterface.h" #include "qxcbscreen.h" +#include "qxcbwindow.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" #include <private/qguiapplication_p.h> #include <QtCore/QMap> @@ -82,6 +84,8 @@ public: insert("appusertime",QXcbNativeInterface::AppUserTime); insert("hintstyle", QXcbNativeInterface::ScreenHintStyle); insert("startupid", QXcbNativeInterface::StartupId); + insert(QByteArrayLiteral("traywindow"), QXcbNativeInterface::TrayWindow); + insert(QByteArrayLiteral("gettimestamp"), QXcbNativeInterface::GetTimestamp); } }; @@ -100,6 +104,36 @@ void QXcbNativeInterface::beep() // For QApplication::beep() xcb_bell(connection, 0); } +static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s) +{ + return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker(); +} + +bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const +{ + return systemTrayTracker(screen); +} + +bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window) +{ + const QPlatformWindow *platformWindow = window->handle(); + if (!platformWindow) + return false; + QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen()); + if (!trayTracker) + return false; + trayTracker->requestSystemTrayWindowDock(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return true; +} + +QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window) +{ + if (const QPlatformWindow *platformWindow = window->handle()) + if (const QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen())) + return trayTracker->systemTrayWindowGlobalGeometry(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return QRect(); +} + void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) { QByteArray lowerCaseResource = resourceString.toLower(); @@ -162,6 +196,14 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q break; case ScreenHintStyle: result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1); + break; + case TrayWindow: + if (QXcbSystemTrayTracker *s = systemTrayTracker(screen)) + result = (void *)quintptr(s->trayWindow()); + break; + case GetTimestamp: + result = getTimestamp(xcbScreen); + break; default: break; } @@ -216,6 +258,11 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen) return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime())); } +void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen) +{ + return reinterpret_cast<void *>(quintptr(screen->connection()->getTimestamp())); +} + void *QXcbNativeInterface::startupId() { QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index e27bfa5a46..86b94e62e4 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -45,6 +45,8 @@ #include <qpa/qplatformnativeinterface.h> #include <xcb/xcb.h> +#include <QtCore/QRect> + QT_BEGIN_NAMESPACE class QWidget; @@ -66,7 +68,9 @@ public: AppTime, AppUserTime, ScreenHintStyle, - StartupId + StartupId, + TrayWindow, + GetTimestamp }; QXcbNativeInterface(); @@ -88,6 +92,7 @@ public: void *graphicsDeviceForWindow(QWindow *window); void *appTime(const QXcbScreen *screen); void *appUserTime(const QXcbScreen *screen); + void *getTimestamp(const QXcbScreen *screen); void *startupId(); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); @@ -95,6 +100,12 @@ public: static void *glxContextForContext(QOpenGLContext *context); Q_INVOKABLE void beep(); + Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const; + Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); + Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); + +signals: + void systemTrayWindowChanged(QScreen *screen); private: const QByteArray m_genericEventFilterType; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 37c6c97bc4..0971b6ca8e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -112,6 +112,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification). }; xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values); diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp new file mode 100644 index 0000000000..24d2feb106 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbsystemtraytracker.h" +#include "qxcbconnection.h" +#include "qxcbscreen.h" + +#include <QtCore/QDebug> +#include <QtCore/QRect> +#include <QtGui/QScreen> + +#include <qpa/qplatformnativeinterface.h> + +QT_BEGIN_NAMESPACE + +enum { + SystemTrayRequestDock = 0, + SystemTrayBeginMessage = 1, + SystemTrayCancelMessage = 2 +}; + +// QXcbSystemTrayTracker provides API for accessing the tray window and tracks +// its lifecyle by listening for its destruction and recreation. +// See http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html + +QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) +{ + // Selection, tray atoms for GNOME, NET WM Specification + const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE); + if (!trayAtom) + return 0; + const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreen()); + const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); + if (!selection) + return 0; + return new QXcbSystemTrayTracker(connection, trayAtom, selection, connection); +} + +QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent) + : QObject(parent) + , m_selection(selection) + , m_trayAtom(trayAtom) + , m_connection(connection) + , m_trayWindow(0) +{ +} + +xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection) +{ + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(connection->xcb_connection(), selection); + xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(connection->xcb_connection(), cookie, 0); + if (!reply) + return 0; + const xcb_window_t result = reply->owner; + free(reply); + return result; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Request a window +// to be docked on the tray. +void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const +{ + xcb_client_message_event_t trayRequest; + memset(&trayRequest, 0, sizeof(trayRequest)); + trayRequest.response_type = XCB_CLIENT_MESSAGE; + trayRequest.format = 32; + trayRequest.window = m_trayWindow; + trayRequest.type = m_trayAtom; + trayRequest.data.data32[0] = XCB_CURRENT_TIME; + trayRequest.data.data32[1] = SystemTrayRequestDock; + trayRequest.data.data32[2] = window; + xcb_send_event(m_connection->xcb_connection(), 0, m_trayWindow, XCB_EVENT_MASK_NO_EVENT, (const char *)&trayRequest); +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return tray window. +xcb_window_t QXcbSystemTrayTracker::trayWindow() +{ + if (!m_trayWindow) { + m_trayWindow = QXcbSystemTrayTracker::locateTrayWindow(m_connection, m_selection); + if (m_trayWindow) { // Listen for DestroyNotify on tray. + m_connection->addWindowEventListener(m_trayWindow, this); + const quint32 mask = XCB_CW_EVENT_MASK; + const quint32 value = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + Q_XCB_CALL(xcb_change_window_attributes(m_connection->xcb_connection(), m_trayWindow, mask, &value)); + } + } + return m_trayWindow; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return the geometry of a +// a window parented on the tray. Determines the global geometry via XCB since mapToGlobal +// does not work for the QWindow parented on the tray. +QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const +{ + xcb_connection_t *conn = m_connection->xcb_connection(); + xcb_get_geometry_reply_t *geomReply = + xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), 0); + if (!geomReply) + return QRect(); + + xcb_translate_coordinates_reply_t *translateReply = + xcb_translate_coordinates_reply(conn, xcb_translate_coordinates(conn, window, m_connection->rootWindow(), 0, 0), 0); + if (!translateReply) { + free(geomReply); + return QRect(); + } + + const QRect result(QPoint(translateReply->dst_x, translateReply->dst_y), QSize(geomReply->width, geomReply->height)); + free(translateReply); + return result; +} + +inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged() +{ + const int screen = m_connection->primaryScreen(); + if (screen >= 0 && screen < m_connection->screens().size()) { + const QPlatformScreen *ps = m_connection->screens().at(screen); + emit systemTrayWindowChanged(ps->screen()); + } +} + +// Client messages with the "MANAGER" atom on the root window indicate creation of a new tray. +void QXcbSystemTrayTracker::notifyManagerClientMessageEvent(const xcb_client_message_event_t *t) +{ + if (t->data.data32[1] == m_selection) + emitSystemTrayWindowChanged(); +} + +// Listen for destruction of the tray. +void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *event) +{ + if (event->window == m_trayWindow) { + m_connection->removeWindowEventListener(m_trayWindow); + m_trayWindow = 0; + emitSystemTrayWindowChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h new file mode 100644 index 0000000000..c6b0a0659e --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBSYSTEMTRAYTRACKER_H +#define QXCBSYSTEMTRAYTRACKER_H + +#include "qxcbconnection.h" + +#include <xcb/xcb.h> + +QT_BEGIN_NAMESPACE + +class QXcbConnection; +class QScreen; + +class QXcbSystemTrayTracker : public QObject, public QXcbWindowEventListener +{ + Q_OBJECT +public: + static QXcbSystemTrayTracker *create(QXcbConnection *connection); + + xcb_window_t trayWindow(); + void requestSystemTrayWindowDock(xcb_window_t window) const; + QRect systemTrayWindowGlobalGeometry(xcb_window_t window) const; + + void notifyManagerClientMessageEvent(const xcb_client_message_event_t *); + + void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *); + +signals: + void systemTrayWindowChanged(QScreen *screen); + +private: + explicit QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent = 0); + static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection); + void emitSystemTrayWindowChanged(); + + const xcb_atom_t m_selection; + const xcb_atom_t m_trayAtom; + QXcbConnection *m_connection; + xcb_window_t m_trayWindow; +}; + +QT_END_NAMESPACE + +#endif // QXCBSYSTEMTRAYTRACKER_H diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 028cd9ab72..35b95b84a1 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1515,8 +1515,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even m_syncValue.hi = event->data.data32[3]; #ifndef QT_NO_WHATSTHIS } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) { - QEvent *e = new QEvent(QEvent::EnterWhatsThisMode); - QGuiApplication::postEvent(QGuiApplication::instance(), e); + QWindowSystemInterface::handleEnterWhatsThisEvent(); #endif } else { qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); @@ -1533,6 +1532,9 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); + } else if (event->type == atom(QXcbAtom::MANAGER) || event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) { + // Ignore _NET_ACTIVE_WINDOW which is received when the user clicks on a system tray icon and + // MANAGER which indicates the creation of a system tray. } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 82995286c4..b198ab1717 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -21,7 +21,8 @@ SOURCES = \ qxcbnativeinterface.cpp \ qxcbcursor.cpp \ qxcbimage.cpp \ - qxcbxsettings.cpp + qxcbxsettings.cpp \ + qxcbsystemtraytracker.cpp HEADERS = \ qxcbclipboard.h \ @@ -38,7 +39,8 @@ HEADERS = \ qxcbnativeinterface.h \ qxcbcursor.h \ qxcbimage.h \ - qxcbxsettings.h + qxcbxsettings.h \ + qxcbsystemtraytracker.h LIBS += -ldl |