| /*************************************************************************** |
| ** |
| ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** 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 The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qqnxglobal.h" |
| |
| #include "qqnxscreeneventhandler.h" |
| #include "qqnxscreeneventthread.h" |
| #include "qqnxintegration.h" |
| #include "qqnxkeytranslator.h" |
| #include "qqnxscreen.h" |
| #include "qqnxscreeneventfilter.h" |
| #include "qqnxscreentraits.h" |
| |
| #include <QDebug> |
| #include <QGuiApplication> |
| |
| #include <errno.h> |
| #include <sys/keycodes.h> |
| |
| #if defined(QQNXSCREENEVENT_DEBUG) |
| #define qScreenEventDebug qDebug |
| #else |
| #define qScreenEventDebug QT_NO_QDEBUG_MACRO |
| #endif |
| |
| static int qtKey(int virtualKey, QChar::Category category) |
| { |
| if (Q_UNLIKELY(category == QChar::Other_NotAssigned)) |
| return virtualKey; |
| else if (category == QChar::Other_PrivateUse) |
| return qtKeyForPrivateUseQnxKey(virtualKey); |
| else |
| return QChar::toUpper(virtualKey); |
| } |
| |
| static QString keyString(int sym, QChar::Category category) |
| { |
| if (Q_UNLIKELY(category == QChar::Other_NotAssigned)) { |
| return QString(); |
| } else if (category == QChar::Other_PrivateUse) { |
| return keyStringForPrivateUseQnxKey(sym); |
| } else { |
| uint ucs4_sym = sym; |
| return QString::fromUcs4(&ucs4_sym, 1); |
| } |
| } |
| |
| static QString capKeyString(int cap, int modifiers, int key) |
| { |
| if (cap >= 0x20 && cap <= 0x0ff) { |
| if (modifiers & KEYMOD_CTRL) |
| return QChar((int)(key & 0x3f)); |
| } |
| return QString(); |
| } |
| |
| template <typename T> |
| static void finishCloseEvent(screen_event_t event) |
| { |
| T t; |
| screen_get_event_property_pv(event, |
| screen_traits<T>::propertyName, |
| reinterpret_cast<void**>(&t)); |
| screen_traits<T>::destroy(t); |
| } |
| |
| static void finishCloseEvent(screen_event_t event) |
| { |
| // Let libscreen know that we're finished with anything that may have been acquired. |
| int objectType = SCREEN_OBJECT_TYPE_CONTEXT; |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType); |
| switch (objectType) { |
| case SCREEN_OBJECT_TYPE_CONTEXT: |
| finishCloseEvent<screen_context_t>(event); |
| break; |
| case SCREEN_OBJECT_TYPE_DEVICE: |
| finishCloseEvent<screen_device_t>(event); |
| break; |
| case SCREEN_OBJECT_TYPE_DISPLAY: |
| // no screen_destroy_display |
| break; |
| case SCREEN_OBJECT_TYPE_GROUP: |
| finishCloseEvent<screen_group_t>(event); |
| break; |
| case SCREEN_OBJECT_TYPE_PIXMAP: |
| finishCloseEvent<screen_pixmap_t>(event); |
| break; |
| case SCREEN_OBJECT_TYPE_SESSION: |
| finishCloseEvent<screen_session_t>(event); |
| break; |
| #if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0) |
| case SCREEN_OBJECT_TYPE_STREAM: |
| finishCloseEvent<screen_stream_t>(event); |
| break; |
| #endif |
| case SCREEN_OBJECT_TYPE_WINDOW: |
| finishCloseEvent<screen_window_t>(event); |
| break; |
| } |
| } |
| |
| QT_BEGIN_NAMESPACE |
| |
| QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration) |
| : m_qnxIntegration(integration) |
| , m_lastButtonState(Qt::NoButton) |
| , m_lastMouseWindow(0) |
| , m_touchDevice(0) |
| , m_eventThread(0) |
| , m_focusLostTimer(-1) |
| { |
| // Create a touch device |
| m_touchDevice = new QTouchDevice; |
| m_touchDevice->setType(QTouchDevice::TouchScreen); |
| m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); |
| QWindowSystemInterface::registerTouchDevice(m_touchDevice); |
| |
| // initialize array of touch points |
| for (int i = 0; i < MaximumTouchPoints; i++) { |
| |
| // map array index to id |
| m_touchPoints[i].id = i; |
| |
| // pressure is not supported - use default |
| m_touchPoints[i].pressure = 1.0; |
| |
| // nothing touching |
| m_touchPoints[i].state = Qt::TouchPointReleased; |
| } |
| } |
| |
| void QQnxScreenEventHandler::addScreenEventFilter(QQnxScreenEventFilter *filter) |
| { |
| m_eventFilters.append(filter); |
| } |
| |
| void QQnxScreenEventHandler::removeScreenEventFilter(QQnxScreenEventFilter *filter) |
| { |
| m_eventFilters.removeOne(filter); |
| } |
| |
| bool QQnxScreenEventHandler::handleEvent(screen_event_t event) |
| { |
| // get the event type |
| int qnxType; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType), |
| "Failed to query event type"); |
| |
| return handleEvent(event, qnxType); |
| } |
| |
| bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType) |
| { |
| switch (qnxType) { |
| case SCREEN_EVENT_MTOUCH_TOUCH: |
| case SCREEN_EVENT_MTOUCH_MOVE: |
| case SCREEN_EVENT_MTOUCH_RELEASE: |
| handleTouchEvent(event, qnxType); |
| break; |
| |
| case SCREEN_EVENT_KEYBOARD: |
| handleKeyboardEvent(event); |
| break; |
| |
| case SCREEN_EVENT_POINTER: |
| handlePointerEvent(event); |
| break; |
| |
| case SCREEN_EVENT_CREATE: |
| handleCreateEvent(event); |
| break; |
| |
| case SCREEN_EVENT_CLOSE: |
| handleCloseEvent(event); |
| break; |
| |
| case SCREEN_EVENT_DISPLAY: |
| handleDisplayEvent(event); |
| break; |
| |
| case SCREEN_EVENT_PROPERTY: |
| handlePropertyEvent(event); |
| break; |
| |
| default: |
| // event ignored |
| qScreenEventDebug("unknown event %d", qnxType); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap) |
| { |
| Q_UNUSED(scan); |
| |
| if (!(flags & KEY_CAP_VALID)) |
| return; |
| |
| // Correct erroneous information. |
| if ((flags & KEY_SYM_VALID) && sym == static_cast<int>(0xFFFFFFFF)) |
| flags &= ~(KEY_SYM_VALID); |
| |
| Qt::KeyboardModifiers qtMod = Qt::NoModifier; |
| if (modifiers & KEYMOD_SHIFT) |
| qtMod |= Qt::ShiftModifier; |
| if (modifiers & KEYMOD_CTRL) |
| qtMod |= Qt::ControlModifier; |
| if (modifiers & KEYMOD_ALT) |
| qtMod |= Qt::AltModifier; |
| if (isKeypadKey(cap)) |
| qtMod |= Qt::KeypadModifier; |
| |
| QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease; |
| |
| int virtualKey = (flags & KEY_SYM_VALID) ? sym : cap; |
| QChar::Category category = QChar::category(virtualKey); |
| int key = qtKey(virtualKey, category); |
| QString keyStr = (flags & KEY_SYM_VALID) ? keyString(sym, category) : |
| capKeyString(cap, modifiers, key); |
| |
| QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, |
| scan, virtualKey, modifiers, keyStr); |
| qScreenEventDebug() << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr; |
| } |
| |
| void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread) |
| { |
| m_eventThread = eventThread; |
| connect(m_eventThread, &QQnxScreenEventThread::eventsPending, |
| this, &QQnxScreenEventHandler::processEvents); |
| } |
| |
| void QQnxScreenEventHandler::processEvents() |
| { |
| if (!m_eventThread) |
| return; |
| |
| screen_event_t event = nullptr; |
| if (screen_create_event(&event) != 0) |
| return; |
| |
| int count = 0; |
| for (;;) { |
| if (screen_get_event(m_eventThread->context(), event, 0) != 0) |
| break; |
| |
| int type = SCREEN_EVENT_NONE; |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type); |
| if (type == SCREEN_EVENT_NONE) |
| break; |
| |
| ++count; |
| #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) |
| qintptr result = 0; |
| #else |
| long result = 0; |
| #endif |
| QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); |
| bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result); |
| if (!handled) |
| handleEvent(event); |
| |
| if (type == SCREEN_EVENT_CLOSE) |
| finishCloseEvent(event); |
| } |
| |
| m_eventThread->armEventsPending(count); |
| screen_destroy_event(event); |
| } |
| |
| void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event) |
| { |
| // get flags of key event |
| int flags; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags), |
| "Failed to query event flags"); |
| |
| // get key code |
| int sym; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &sym), |
| "Failed to query event sym"); |
| |
| int modifiers; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_MODIFIERS, &modifiers), |
| "Failed to query event modifieres"); |
| |
| int scan; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SCAN, &scan), |
| "Failed to query event scan"); |
| |
| int cap; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap), |
| "Failed to query event cap"); |
| |
| int sequenceId = 0; |
| bool inject = true; |
| |
| Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) { |
| if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) { |
| inject = false; |
| break; |
| } |
| } |
| |
| if (inject) |
| injectKeyboardEvent(flags, sym, modifiers, scan, cap); |
| } |
| |
| void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) |
| { |
| errno = 0; |
| |
| // Query the window that was clicked |
| screen_window_t qnxWindow; |
| void *handle; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle), |
| "Failed to query event window"); |
| |
| qnxWindow = static_cast<screen_window_t>(handle); |
| |
| // Query the button states |
| int buttonState = 0; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState), |
| "Failed to query event button state"); |
| |
| // Query the window position |
| int windowPos[2]; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos), |
| "Failed to query event window position"); |
| |
| // Query the screen position |
| int pos[2]; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos), |
| "Failed to query event position"); |
| |
| // Query the wheel delta |
| int wheelDelta = 0; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta), |
| "Failed to query event wheel delta"); |
| |
| // Map window handle to top-level QWindow |
| QWindow *w = QQnxIntegration::instance()->window(qnxWindow); |
| |
| // Generate enter and leave events as needed. |
| if (qnxWindow != m_lastMouseWindow) { |
| QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow); |
| |
| if (wOld) { |
| QWindowSystemInterface::handleLeaveEvent(wOld); |
| qScreenEventDebug() << "Qt leave, w=" << wOld; |
| } |
| |
| if (w) { |
| QWindowSystemInterface::handleEnterEvent(w); |
| qScreenEventDebug() << "Qt enter, w=" << w; |
| } |
| } |
| |
| m_lastMouseWindow = qnxWindow; |
| |
| // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale |
| // this via a system preference at some point. But for now this is a sane value and makes |
| // the wheel usable. |
| wheelDelta *= -10; |
| |
| // convert point to local coordinates |
| QPoint globalPoint(pos[0], pos[1]); |
| QPoint localPoint(windowPos[0], windowPos[1]); |
| |
| // Convert buttons. |
| // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit, |
| // so we may receive events as shown. (If this is wrong, the fix is easy.) |
| // QNX Button mask is 8 buttons wide, with a maximum value of x080. |
| Qt::MouseButtons buttons = Qt::NoButton; |
| if (buttonState & 0x01) |
| buttons |= Qt::LeftButton; |
| if (buttonState & 0x02) |
| buttons |= Qt::MidButton; |
| if (buttonState & 0x04) |
| buttons |= Qt::RightButton; |
| if (buttonState & 0x08) |
| buttons |= Qt::ExtraButton1; // AKA 'Qt::BackButton' |
| if (buttonState & 0x10) |
| buttons |= Qt::ExtraButton2; // AKA 'Qt::ForwardButton' |
| if (buttonState & 0x20) |
| buttons |= Qt::ExtraButton3; |
| if (buttonState & 0x40) |
| buttons |= Qt::ExtraButton4; |
| if (buttonState & 0x80) |
| buttons |= Qt::ExtraButton5; |
| |
| if (w) { |
| // Inject mouse event into Qt only if something has changed. |
| if (m_lastGlobalMousePoint != globalPoint || |
| m_lastLocalMousePoint != localPoint || |
| m_lastButtonState != buttons) { |
| if (m_lastButtonState != 0 && buttons == 0) |
| (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent(); |
| QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); |
| qScreenEventDebug() << "Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons); |
| } |
| |
| if (wheelDelta) { |
| // Screen only supports a single wheel, so we will assume Vertical orientation for |
| // now since that is pretty much standard. |
| QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical); |
| qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta); |
| } |
| } |
| |
| m_lastGlobalMousePoint = globalPoint; |
| m_lastLocalMousePoint = localPoint; |
| m_lastButtonState = buttons; |
| } |
| |
| void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) |
| { |
| // get display coordinates of touch |
| int pos[2]; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos), |
| "Failed to query event position"); |
| |
| QCursor::setPos(pos[0], pos[1]); |
| |
| // get window coordinates of touch |
| int windowPos[2]; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos), |
| "Failed to query event window position"); |
| |
| // determine which finger touched |
| int touchId; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId), |
| "Failed to query event touch id"); |
| |
| // determine which window was touched |
| void *handle; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle), |
| "Failed to query event window"); |
| |
| errno = 0; |
| int touchArea[2]; |
| Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SIZE, touchArea), |
| "Failed to query event touch area"); |
| |
| int touchPressure; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_PRESSURE, &touchPressure), |
| "Failed to query event touch pressure"); |
| |
| screen_window_t qnxWindow = static_cast<screen_window_t>(handle); |
| |
| // check if finger is valid |
| if (touchId < MaximumTouchPoints) { |
| |
| // Map window handle to top-level QWindow |
| QWindow *w = QQnxIntegration::instance()->window(qnxWindow); |
| |
| // Generate enter and leave events as needed. |
| if (qnxWindow != m_lastMouseWindow) { |
| QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow); |
| |
| if (wOld) { |
| QWindowSystemInterface::handleLeaveEvent(wOld); |
| qScreenEventDebug() << "Qt leave, w=" << wOld; |
| } |
| |
| if (w) { |
| QWindowSystemInterface::handleEnterEvent(w); |
| qScreenEventDebug() << "Qt enter, w=" << w; |
| } |
| } |
| m_lastMouseWindow = qnxWindow; |
| |
| if (w) { |
| if (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) |
| (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent(); |
| |
| // get size of screen which contains window |
| QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w); |
| QSizeF screenSize = platformScreen->geometry().size(); |
| |
| // update cached position of current touch point |
| m_touchPoints[touchId].normalPosition = |
| QPointF(static_cast<qreal>(pos[0]) / screenSize.width(), |
| static_cast<qreal>(pos[1]) / screenSize.height()); |
| |
| m_touchPoints[touchId].area = QRectF(w->geometry().left() + windowPos[0] - (touchArea[0]>>1), |
| w->geometry().top() + windowPos[1] - (touchArea[1]>>1), |
| (touchArea[0]>>1), (touchArea[1]>>1)); |
| QWindow *parent = w->parent(); |
| while (parent) { |
| m_touchPoints[touchId].area.translate(parent->geometry().topLeft()); |
| parent = parent->parent(); |
| } |
| |
| //Qt expects the pressure between 0 and 1. There is however no definit upper limit for |
| //the integer value of touch event pressure. The 200 was determined by experiment, it |
| //usually does not get higher than that. |
| m_touchPoints[touchId].pressure = static_cast<qreal>(touchPressure)/200.0; |
| // Can happen, because there is no upper limit for pressure |
| if (m_touchPoints[touchId].pressure > 1) |
| m_touchPoints[touchId].pressure = 1; |
| |
| // determine event type and update state of current touch point |
| QEvent::Type type = QEvent::None; |
| switch (qnxType) { |
| case SCREEN_EVENT_MTOUCH_TOUCH: |
| m_touchPoints[touchId].state = Qt::TouchPointPressed; |
| type = QEvent::TouchBegin; |
| break; |
| case SCREEN_EVENT_MTOUCH_MOVE: |
| m_touchPoints[touchId].state = Qt::TouchPointMoved; |
| type = QEvent::TouchUpdate; |
| break; |
| case SCREEN_EVENT_MTOUCH_RELEASE: |
| m_touchPoints[touchId].state = Qt::TouchPointReleased; |
| type = QEvent::TouchEnd; |
| break; |
| } |
| |
| // build list of active touch points |
| QList<QWindowSystemInterface::TouchPoint> pointList; |
| for (int i = 0; i < MaximumTouchPoints; i++) { |
| if (i == touchId) { |
| // current touch point is always active |
| pointList.append(m_touchPoints[i]); |
| } else if (m_touchPoints[i].state != Qt::TouchPointReleased) { |
| // finger is down but did not move |
| m_touchPoints[i].state = Qt::TouchPointStationary; |
| pointList.append(m_touchPoints[i]); |
| } |
| } |
| |
| // inject event into Qt |
| QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList); |
| qScreenEventDebug() << "Qt touch, w =" << w |
| << ", p=" << m_touchPoints[touchId].area.topLeft() |
| << ", t=" << type; |
| } |
| } |
| } |
| |
| void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event) |
| { |
| screen_window_t window = 0; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window), |
| "Failed to query window property"); |
| |
| Q_EMIT windowClosed(window); |
| |
| // Map window handle to top-level QWindow |
| QWindow *w = QQnxIntegration::instance()->window(window); |
| if (w != 0) |
| QWindowSystemInterface::handleCloseEvent(w); |
| } |
| |
| void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event) |
| { |
| screen_window_t window = 0; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window), |
| "Failed to query window property"); |
| |
| Q_EMIT newWindowCreated(window); |
| } |
| |
| void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event) |
| { |
| screen_display_t nativeDisplay = 0; |
| if (screen_get_event_property_pv(event, SCREEN_PROPERTY_DISPLAY, (void **)&nativeDisplay) != 0) { |
| qWarning("QQnx: failed to query display property, errno=%d", errno); |
| return; |
| } |
| |
| int isAttached = 0; |
| if (screen_get_event_property_iv(event, SCREEN_PROPERTY_ATTACHED, &isAttached) != 0) { |
| qWarning("QQnx: failed to query display attached property, errno=%d", errno); |
| return; |
| } |
| |
| qScreenEventDebug() << "display attachment is now:" << isAttached; |
| QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay); |
| |
| if (!screen) { |
| if (isAttached) { |
| int val[2]; |
| screen_get_display_property_iv(nativeDisplay, SCREEN_PROPERTY_SIZE, val); |
| if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event |
| return; |
| |
| qScreenEventDebug("creating new QQnxScreen for newly attached display"); |
| m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */); |
| } |
| } else if (!isAttached) { |
| // We never remove the primary display, the qpa plugin doesn't support that and it crashes. |
| // To support it, this would be needed: |
| // - Adjust all qnx qpa code which uses screens |
| // - Make QWidgetRepaintManager not dereference a null paint device |
| // - Create platform resources ( QQnxWindow ) for all QWindow because they would be deleted |
| // when you delete the screen |
| |
| if (!screen->isPrimaryScreen()) { |
| // libscreen display is deactivated, let's remove the QQnxScreen / QScreen |
| qScreenEventDebug("removing display"); |
| m_qnxIntegration->removeDisplay(screen); |
| } |
| } |
| } |
| |
| void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event) |
| { |
| errno = 0; |
| int objectType; |
| Q_SCREEN_CHECKERROR( |
| screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType), |
| "Failed to query object type property"); |
| |
| if (objectType != SCREEN_OBJECT_TYPE_WINDOW) |
| return; |
| |
| errno = 0; |
| screen_window_t window = 0; |
| if (Q_UNLIKELY(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)) |
| qFatal("QQnx: failed to query window property, errno=%d", errno); |
| |
| errno = 0; |
| int property; |
| if (Q_UNLIKELY(screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0)) |
| qFatal("QQnx: failed to query window property, errno=%d", errno); |
| |
| switch (property) { |
| case SCREEN_PROPERTY_FOCUS: |
| handleKeyboardFocusPropertyEvent(window); |
| break; |
| case SCREEN_PROPERTY_SIZE: |
| case SCREEN_PROPERTY_POSITION: |
| handleGeometryPropertyEvent(window); |
| break; |
| default: |
| // event ignored |
| qScreenEventDebug() << "Ignore property event for property: " << property; |
| } |
| } |
| |
| void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t window) |
| { |
| errno = 0; |
| int focus = 0; |
| if (Q_UNLIKELY(window && screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focus) != 0)) |
| qFatal("QQnx: failed to query keyboard focus property, errno=%d", errno); |
| |
| QWindow *focusWindow = QQnxIntegration::instance()->window(window); |
| |
| if (m_focusLostTimer != -1) { |
| killTimer(m_focusLostTimer); |
| m_focusLostTimer = -1; |
| } |
| |
| if (focus && focusWindow != QGuiApplication::focusWindow()) |
| QWindowSystemInterface::handleWindowActivated(focusWindow); |
| else if (!focus && focusWindow == QGuiApplication::focusWindow()) |
| m_focusLostTimer = startTimer(50); |
| } |
| |
| void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window) |
| { |
| int pos[2]; |
| if (screen_get_window_property_iv(window, SCREEN_PROPERTY_POSITION, pos) != 0) { |
| qFatal("QQnx: failed to query window property, errno=%d", errno); |
| } |
| |
| int size[2]; |
| if (screen_get_window_property_iv(window, SCREEN_PROPERTY_SIZE, size) != 0) { |
| qFatal("QQnx: failed to query window property, errno=%d", errno); |
| } |
| |
| QRect rect(pos[0], pos[1], size[0], size[1]); |
| QWindow *qtWindow = QQnxIntegration::instance()->window(window); |
| if (qtWindow) { |
| qtWindow->setGeometry(rect); |
| QWindowSystemInterface::handleGeometryChange(qtWindow, rect); |
| } |
| |
| qScreenEventDebug() << qtWindow << "moved to" << rect; |
| } |
| |
| void QQnxScreenEventHandler::timerEvent(QTimerEvent *event) |
| { |
| if (event->timerId() == m_focusLostTimer) { |
| killTimer(m_focusLostTimer); |
| m_focusLostTimer = -1; |
| event->accept(); |
| } else { |
| QObject::timerEvent(event); |
| } |
| } |
| |
| #include "moc_qqnxscreeneventhandler.cpp" |
| |
| QT_END_NAMESPACE |