1 /***************************************************************************
2 **
3 ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qqnxglobal.h"
41 
42 #include "qqnxscreeneventhandler.h"
43 #include "qqnxscreeneventthread.h"
44 #include "qqnxintegration.h"
45 #include "qqnxkeytranslator.h"
46 #include "qqnxscreen.h"
47 #include "qqnxscreeneventfilter.h"
48 #include "qqnxscreentraits.h"
49 
50 #include <QDebug>
51 #include <QGuiApplication>
52 
53 #include <errno.h>
54 #include <sys/keycodes.h>
55 
56 #if defined(QQNXSCREENEVENT_DEBUG)
57 #define qScreenEventDebug qDebug
58 #else
59 #define qScreenEventDebug QT_NO_QDEBUG_MACRO
60 #endif
61 
qtKey(int virtualKey,QChar::Category category)62 static int qtKey(int virtualKey, QChar::Category category)
63 {
64     if (Q_UNLIKELY(category == QChar::Other_NotAssigned))
65         return virtualKey;
66     else if (category == QChar::Other_PrivateUse)
67         return qtKeyForPrivateUseQnxKey(virtualKey);
68     else
69         return QChar::toUpper(virtualKey);
70 }
71 
keyString(int sym,QChar::Category category)72 static QString keyString(int sym, QChar::Category category)
73 {
74     if (Q_UNLIKELY(category == QChar::Other_NotAssigned)) {
75         return QString();
76     } else if (category == QChar::Other_PrivateUse) {
77         return keyStringForPrivateUseQnxKey(sym);
78     } else {
79         uint ucs4_sym = sym;
80         return QString::fromUcs4(&ucs4_sym, 1);
81     }
82 }
83 
capKeyString(int cap,int modifiers,int key)84 static QString capKeyString(int cap, int modifiers, int key)
85 {
86     if (cap >= 0x20 && cap <= 0x0ff) {
87         if (modifiers & KEYMOD_CTRL)
88             return QChar((int)(key & 0x3f));
89     }
90     return QString();
91 }
92 
93 template <typename T>
finishCloseEvent(screen_event_t event)94 static void finishCloseEvent(screen_event_t event)
95 {
96     T t;
97     screen_get_event_property_pv(event,
98             screen_traits<T>::propertyName,
99             reinterpret_cast<void**>(&t));
100     screen_traits<T>::destroy(t);
101 }
102 
finishCloseEvent(screen_event_t event)103 static void finishCloseEvent(screen_event_t event)
104 {
105     // Let libscreen know that we're finished with anything that may have been acquired.
106     int objectType = SCREEN_OBJECT_TYPE_CONTEXT;
107     screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType);
108     switch (objectType) {
109     case SCREEN_OBJECT_TYPE_CONTEXT:
110         finishCloseEvent<screen_context_t>(event);
111         break;
112     case SCREEN_OBJECT_TYPE_DEVICE:
113         finishCloseEvent<screen_device_t>(event);
114         break;
115     case SCREEN_OBJECT_TYPE_DISPLAY:
116         // no screen_destroy_display
117         break;
118     case SCREEN_OBJECT_TYPE_GROUP:
119         finishCloseEvent<screen_group_t>(event);
120         break;
121     case SCREEN_OBJECT_TYPE_PIXMAP:
122         finishCloseEvent<screen_pixmap_t>(event);
123         break;
124     case SCREEN_OBJECT_TYPE_SESSION:
125         finishCloseEvent<screen_session_t>(event);
126         break;
127 #if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0)
128     case SCREEN_OBJECT_TYPE_STREAM:
129         finishCloseEvent<screen_stream_t>(event);
130         break;
131 #endif
132     case SCREEN_OBJECT_TYPE_WINDOW:
133         finishCloseEvent<screen_window_t>(event);
134         break;
135     }
136 }
137 
138 QT_BEGIN_NAMESPACE
139 
QQnxScreenEventHandler(QQnxIntegration * integration)140 QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
141     : m_qnxIntegration(integration)
142     , m_lastButtonState(Qt::NoButton)
143     , m_lastMouseWindow(0)
144     , m_touchDevice(0)
145     , m_eventThread(0)
146     , m_focusLostTimer(-1)
147 {
148     // Create a touch device
149     m_touchDevice = new QTouchDevice;
150     m_touchDevice->setType(QTouchDevice::TouchScreen);
151     m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
152     QWindowSystemInterface::registerTouchDevice(m_touchDevice);
153 
154     // initialize array of touch points
155     for (int i = 0; i < MaximumTouchPoints; i++) {
156 
157         // map array index to id
158         m_touchPoints[i].id = i;
159 
160         // pressure is not supported - use default
161         m_touchPoints[i].pressure = 1.0;
162 
163         // nothing touching
164         m_touchPoints[i].state = Qt::TouchPointReleased;
165     }
166 }
167 
addScreenEventFilter(QQnxScreenEventFilter * filter)168 void QQnxScreenEventHandler::addScreenEventFilter(QQnxScreenEventFilter *filter)
169 {
170     m_eventFilters.append(filter);
171 }
172 
removeScreenEventFilter(QQnxScreenEventFilter * filter)173 void QQnxScreenEventHandler::removeScreenEventFilter(QQnxScreenEventFilter *filter)
174 {
175     m_eventFilters.removeOne(filter);
176 }
177 
handleEvent(screen_event_t event)178 bool QQnxScreenEventHandler::handleEvent(screen_event_t event)
179 {
180     // get the event type
181     int qnxType;
182     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType),
183                         "Failed to query event type");
184 
185     return handleEvent(event, qnxType);
186 }
187 
handleEvent(screen_event_t event,int qnxType)188 bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
189 {
190     switch (qnxType) {
191     case SCREEN_EVENT_MTOUCH_TOUCH:
192     case SCREEN_EVENT_MTOUCH_MOVE:
193     case SCREEN_EVENT_MTOUCH_RELEASE:
194         handleTouchEvent(event, qnxType);
195         break;
196 
197     case SCREEN_EVENT_KEYBOARD:
198         handleKeyboardEvent(event);
199         break;
200 
201     case SCREEN_EVENT_POINTER:
202         handlePointerEvent(event);
203         break;
204 
205     case SCREEN_EVENT_CREATE:
206         handleCreateEvent(event);
207         break;
208 
209     case SCREEN_EVENT_CLOSE:
210         handleCloseEvent(event);
211         break;
212 
213     case SCREEN_EVENT_DISPLAY:
214         handleDisplayEvent(event);
215         break;
216 
217     case SCREEN_EVENT_PROPERTY:
218         handlePropertyEvent(event);
219         break;
220 
221     default:
222         // event ignored
223         qScreenEventDebug("unknown event %d", qnxType);
224         return false;
225     }
226 
227     return true;
228 }
229 
injectKeyboardEvent(int flags,int sym,int modifiers,int scan,int cap)230 void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
231 {
232     Q_UNUSED(scan);
233 
234     if (!(flags & KEY_CAP_VALID))
235         return;
236 
237     // Correct erroneous information.
238     if ((flags & KEY_SYM_VALID) && sym == static_cast<int>(0xFFFFFFFF))
239         flags &= ~(KEY_SYM_VALID);
240 
241     Qt::KeyboardModifiers qtMod = Qt::NoModifier;
242     if (modifiers & KEYMOD_SHIFT)
243         qtMod |= Qt::ShiftModifier;
244     if (modifiers & KEYMOD_CTRL)
245         qtMod |= Qt::ControlModifier;
246     if (modifiers & KEYMOD_ALT)
247         qtMod |= Qt::AltModifier;
248     if (isKeypadKey(cap))
249         qtMod |= Qt::KeypadModifier;
250 
251     QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
252 
253     int virtualKey = (flags & KEY_SYM_VALID) ? sym : cap;
254     QChar::Category category = QChar::category(virtualKey);
255     int key = qtKey(virtualKey, category);
256     QString keyStr = (flags & KEY_SYM_VALID) ? keyString(sym, category) :
257                                                capKeyString(cap, modifiers, key);
258 
259     QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod,
260             scan, virtualKey, modifiers, keyStr, flags & KEY_REPEAT);
261     qScreenEventDebug() << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
262 }
263 
setScreenEventThread(QQnxScreenEventThread * eventThread)264 void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
265 {
266     m_eventThread = eventThread;
267     connect(m_eventThread, &QQnxScreenEventThread::eventsPending,
268             this, &QQnxScreenEventHandler::processEvents);
269 }
270 
processEvents()271 void QQnxScreenEventHandler::processEvents()
272 {
273     if (!m_eventThread)
274         return;
275 
276     screen_event_t event = nullptr;
277     if (screen_create_event(&event) != 0)
278         return;
279 
280     int count = 0;
281     for (;;) {
282         if (screen_get_event(m_eventThread->context(), event, 0) != 0)
283             break;
284 
285         int type = SCREEN_EVENT_NONE;
286         screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
287         if (type == SCREEN_EVENT_NONE)
288             break;
289 
290         ++count;
291 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
292         qintptr result = 0;
293 #else
294         long result = 0;
295 #endif
296         QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
297         bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
298         if (!handled)
299             handleEvent(event);
300 
301         if (type == SCREEN_EVENT_CLOSE)
302             finishCloseEvent(event);
303     }
304 
305     m_eventThread->armEventsPending(count);
306     screen_destroy_event(event);
307 }
308 
handleKeyboardEvent(screen_event_t event)309 void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
310 {
311     // get flags of key event
312     int flags;
313     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags),
314                         "Failed to query event flags");
315 
316     // get key code
317     int sym;
318     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &sym),
319                         "Failed to query event sym");
320 
321     int modifiers;
322     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_MODIFIERS, &modifiers),
323                         "Failed to query event modifieres");
324 
325     int scan;
326     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SCAN, &scan),
327                         "Failed to query event scan");
328 
329     int cap;
330     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap),
331                         "Failed to query event cap");
332 
333     int sequenceId = 0;
334     bool inject = true;
335 
336     Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) {
337         if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) {
338             inject = false;
339             break;
340         }
341     }
342 
343     if (inject)
344         injectKeyboardEvent(flags, sym, modifiers, scan, cap);
345 }
346 
handlePointerEvent(screen_event_t event)347 void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
348 {
349     errno = 0;
350 
351     // Query the window that was clicked
352     screen_window_t qnxWindow;
353     void *handle;
354     Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle),
355                         "Failed to query event window");
356 
357     qnxWindow = static_cast<screen_window_t>(handle);
358 
359     // Query the button states
360     int buttonState = 0;
361     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState),
362                         "Failed to query event button state");
363 
364     // Query the window position
365     int windowPos[2];
366     Q_SCREEN_CHECKERROR(
367             screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos),
368             "Failed to query event window position");
369 
370     // Query the screen position
371     int pos[2];
372     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos),
373                         "Failed to query event position");
374 
375     // Query the wheel delta
376     int wheelDelta = 0;
377     Q_SCREEN_CHECKERROR(
378             screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta),
379             "Failed to query event wheel delta");
380 
381     // Map window handle to top-level QWindow
382     QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
383 
384     // Generate enter and leave events as needed.
385     if (qnxWindow != m_lastMouseWindow) {
386         QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
387 
388         if (wOld) {
389             QWindowSystemInterface::handleLeaveEvent(wOld);
390             qScreenEventDebug() << "Qt leave, w=" << wOld;
391         }
392 
393         if (w) {
394             QWindowSystemInterface::handleEnterEvent(w);
395             qScreenEventDebug() << "Qt enter, w=" << w;
396         }
397     }
398 
399     m_lastMouseWindow = qnxWindow;
400 
401     // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale
402     // this via a system preference at some point. But for now this is a sane value and makes
403     // the wheel usable.
404     wheelDelta *= -10;
405 
406     // convert point to local coordinates
407     QPoint globalPoint(pos[0], pos[1]);
408     QPoint localPoint(windowPos[0], windowPos[1]);
409 
410     // Convert buttons.
411     // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit,
412     // so we may receive events as shown. (If this is wrong, the fix is easy.)
413     // QNX Button mask is 8 buttons wide, with a maximum value of x080.
414     Qt::MouseButtons buttons = Qt::NoButton;
415     if (buttonState & 0x01)
416         buttons |= Qt::LeftButton;
417     if (buttonState & 0x02)
418         buttons |= Qt::MidButton;
419     if (buttonState & 0x04)
420         buttons |= Qt::RightButton;
421     if (buttonState & 0x08)
422         buttons |= Qt::ExtraButton1;    // AKA 'Qt::BackButton'
423     if (buttonState & 0x10)
424         buttons |= Qt::ExtraButton2;    // AKA 'Qt::ForwardButton'
425     if (buttonState & 0x20)
426         buttons |= Qt::ExtraButton3;
427     if (buttonState & 0x40)
428         buttons |= Qt::ExtraButton4;
429     if (buttonState & 0x80)
430         buttons |= Qt::ExtraButton5;
431 
432     if (w) {
433         // Inject mouse event into Qt only if something has changed.
434         if (m_lastGlobalMousePoint != globalPoint ||
435             m_lastLocalMousePoint != localPoint ||
436             m_lastButtonState != buttons) {
437             if (m_lastButtonState != 0 && buttons == 0)
438                 (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent();
439             QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
440             qScreenEventDebug() << "Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons);
441         }
442 
443         if (wheelDelta) {
444             // Screen only supports a single wheel, so we will assume Vertical orientation for
445             // now since that is pretty much standard.
446             QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical);
447             qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
448         }
449     }
450 
451     m_lastGlobalMousePoint = globalPoint;
452     m_lastLocalMousePoint = localPoint;
453     m_lastButtonState = buttons;
454 }
455 
handleTouchEvent(screen_event_t event,int qnxType)456 void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
457 {
458     // get display coordinates of touch
459     int pos[2];
460     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos),
461                         "Failed to query event position");
462 
463     QCursor::setPos(pos[0], pos[1]);
464 
465     // get window coordinates of touch
466     int windowPos[2];
467     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos),
468                         "Failed to query event window position");
469 
470     // determine which finger touched
471     int touchId;
472     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId),
473                         "Failed to query event touch id");
474 
475     // determine which window was touched
476     void *handle;
477     Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle),
478                         "Failed to query event window");
479 
480     errno = 0;
481     int touchArea[2];
482     Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SIZE, touchArea),
483                         "Failed to query event touch area");
484 
485     int touchPressure;
486     Q_SCREEN_CHECKERROR(
487             screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_PRESSURE, &touchPressure),
488             "Failed to query event touch pressure");
489 
490     screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
491 
492     // check if finger is valid
493     if (touchId < MaximumTouchPoints) {
494 
495         // Map window handle to top-level QWindow
496         QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
497 
498         // Generate enter and leave events as needed.
499         if (qnxWindow != m_lastMouseWindow) {
500             QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
501 
502             if (wOld) {
503                 QWindowSystemInterface::handleLeaveEvent(wOld);
504                 qScreenEventDebug() << "Qt leave, w=" << wOld;
505             }
506 
507             if (w) {
508                 QWindowSystemInterface::handleEnterEvent(w);
509                 qScreenEventDebug() << "Qt enter, w=" << w;
510             }
511         }
512         m_lastMouseWindow = qnxWindow;
513 
514         if (w) {
515             if (qnxType == SCREEN_EVENT_MTOUCH_RELEASE)
516                 (static_cast<QQnxWindow *>(w->handle()))->handleActivationEvent();
517 
518             // get size of screen which contains window
519             QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
520             QSizeF screenSize = platformScreen->geometry().size();
521 
522             // update cached position of current touch point
523             m_touchPoints[touchId].normalPosition =
524                             QPointF(static_cast<qreal>(pos[0]) / screenSize.width(),
525                                     static_cast<qreal>(pos[1]) / screenSize.height());
526 
527             m_touchPoints[touchId].area = QRectF(w->geometry().left() + windowPos[0] - (touchArea[0]>>1),
528                                                  w->geometry().top()  + windowPos[1] - (touchArea[1]>>1),
529                                                  (touchArea[0]>>1), (touchArea[1]>>1));
530             QWindow *parent = w->parent();
531             while (parent) {
532                 m_touchPoints[touchId].area.translate(parent->geometry().topLeft());
533                 parent = parent->parent();
534             }
535 
536             //Qt expects the pressure between 0 and 1. There is however no definit upper limit for
537             //the integer value of touch event pressure. The 200 was determined by experiment, it
538             //usually does not get higher than that.
539             m_touchPoints[touchId].pressure = static_cast<qreal>(touchPressure)/200.0;
540             // Can happen, because there is no upper limit for pressure
541             if (m_touchPoints[touchId].pressure > 1)
542                 m_touchPoints[touchId].pressure = 1;
543 
544             // determine event type and update state of current touch point
545             QEvent::Type type = QEvent::None;
546             switch (qnxType) {
547             case SCREEN_EVENT_MTOUCH_TOUCH:
548                 m_touchPoints[touchId].state = Qt::TouchPointPressed;
549                 type = QEvent::TouchBegin;
550                 break;
551             case SCREEN_EVENT_MTOUCH_MOVE:
552                 m_touchPoints[touchId].state = Qt::TouchPointMoved;
553                 type = QEvent::TouchUpdate;
554                 break;
555             case SCREEN_EVENT_MTOUCH_RELEASE:
556                 m_touchPoints[touchId].state = Qt::TouchPointReleased;
557                 type = QEvent::TouchEnd;
558                 break;
559             }
560 
561             // build list of active touch points
562             QList<QWindowSystemInterface::TouchPoint> pointList;
563             for (int i = 0; i < MaximumTouchPoints; i++) {
564                 if (i == touchId) {
565                     // current touch point is always active
566                     pointList.append(m_touchPoints[i]);
567                 } else if (m_touchPoints[i].state != Qt::TouchPointReleased) {
568                     // finger is down but did not move
569                     m_touchPoints[i].state = Qt::TouchPointStationary;
570                     pointList.append(m_touchPoints[i]);
571                 }
572             }
573 
574             // inject event into Qt
575             QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
576             qScreenEventDebug() << "Qt touch, w =" << w
577                                 << ", p=" << m_touchPoints[touchId].area.topLeft()
578                                 << ", t=" << type;
579         }
580     }
581 }
582 
handleCloseEvent(screen_event_t event)583 void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
584 {
585     screen_window_t window = 0;
586     Q_SCREEN_CHECKERROR(
587             screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window),
588             "Failed to query window property");
589 
590     Q_EMIT windowClosed(window);
591 
592     // Map window handle to top-level QWindow
593     QWindow *w = QQnxIntegration::instance()->window(window);
594     if (w != 0)
595         QWindowSystemInterface::handleCloseEvent(w);
596 }
597 
handleCreateEvent(screen_event_t event)598 void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event)
599 {
600     screen_window_t window = 0;
601     Q_SCREEN_CHECKERROR(
602             screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window),
603             "Failed to query window property");
604 
605     Q_EMIT newWindowCreated(window);
606 }
607 
handleDisplayEvent(screen_event_t event)608 void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
609 {
610     screen_display_t nativeDisplay = 0;
611     if (screen_get_event_property_pv(event, SCREEN_PROPERTY_DISPLAY, (void **)&nativeDisplay) != 0) {
612         qWarning("QQnx: failed to query display property, errno=%d", errno);
613         return;
614     }
615 
616     int isAttached = 0;
617     if (screen_get_event_property_iv(event, SCREEN_PROPERTY_ATTACHED, &isAttached) != 0) {
618         qWarning("QQnx: failed to query display attached property, errno=%d", errno);
619         return;
620     }
621 
622     qScreenEventDebug() << "display attachment is now:" << isAttached;
623     QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay);
624 
625     if (!screen) {
626         if (isAttached) {
627             int val[2];
628             screen_get_display_property_iv(nativeDisplay, SCREEN_PROPERTY_SIZE, val);
629             if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event
630                 return;
631 
632             qScreenEventDebug("creating new QQnxScreen for newly attached display");
633             m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */);
634         }
635     } else if (!isAttached) {
636         // We never remove the primary display, the qpa plugin doesn't support that and it crashes.
637         // To support it, this would be needed:
638         // - Adjust all qnx qpa code which uses screens
639         // - Make QWidgetRepaintManager not dereference a null paint device
640         // - Create platform resources ( QQnxWindow ) for all QWindow because they would be deleted
641         //   when you delete the screen
642 
643         if (!screen->isPrimaryScreen()) {
644             // libscreen display is deactivated, let's remove the QQnxScreen / QScreen
645             qScreenEventDebug("removing display");
646             m_qnxIntegration->removeDisplay(screen);
647         }
648     }
649 }
650 
handlePropertyEvent(screen_event_t event)651 void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event)
652 {
653     errno = 0;
654     int objectType;
655     Q_SCREEN_CHECKERROR(
656             screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType),
657             "Failed to query object type property");
658 
659     if (objectType != SCREEN_OBJECT_TYPE_WINDOW)
660         return;
661 
662     errno = 0;
663     screen_window_t window = 0;
664     if (Q_UNLIKELY(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0))
665         qFatal("QQnx: failed to query window property, errno=%d", errno);
666 
667     errno = 0;
668     int property;
669     if (Q_UNLIKELY(screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0))
670         qFatal("QQnx: failed to query window property, errno=%d", errno);
671 
672     switch (property) {
673     case SCREEN_PROPERTY_FOCUS:
674         handleKeyboardFocusPropertyEvent(window);
675         break;
676     case SCREEN_PROPERTY_SIZE:
677     case SCREEN_PROPERTY_POSITION:
678         handleGeometryPropertyEvent(window);
679         break;
680     default:
681         // event ignored
682         qScreenEventDebug() << "Ignore property event for property: " << property;
683     }
684 }
685 
handleKeyboardFocusPropertyEvent(screen_window_t window)686 void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t window)
687 {
688     errno = 0;
689     int focus = 0;
690     if (Q_UNLIKELY(window && screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focus) != 0))
691         qFatal("QQnx: failed to query keyboard focus property, errno=%d", errno);
692 
693     QWindow *focusWindow = QQnxIntegration::instance()->window(window);
694 
695     if (m_focusLostTimer != -1) {
696         killTimer(m_focusLostTimer);
697         m_focusLostTimer = -1;
698     }
699 
700     if (focus && focusWindow != QGuiApplication::focusWindow())
701         QWindowSystemInterface::handleWindowActivated(focusWindow);
702     else if (!focus && focusWindow == QGuiApplication::focusWindow())
703         m_focusLostTimer = startTimer(50);
704 }
705 
handleGeometryPropertyEvent(screen_window_t window)706 void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window)
707 {
708     int pos[2];
709     if (screen_get_window_property_iv(window, SCREEN_PROPERTY_POSITION, pos) != 0) {
710         qFatal("QQnx: failed to query window property, errno=%d", errno);
711     }
712 
713     int size[2];
714     if (screen_get_window_property_iv(window, SCREEN_PROPERTY_SIZE, size) != 0) {
715         qFatal("QQnx: failed to query window property, errno=%d", errno);
716     }
717 
718     QRect rect(pos[0], pos[1], size[0], size[1]);
719     QWindow *qtWindow = QQnxIntegration::instance()->window(window);
720     if (qtWindow) {
721         qtWindow->setGeometry(rect);
722         QWindowSystemInterface::handleGeometryChange(qtWindow, rect);
723     }
724 
725     qScreenEventDebug() << qtWindow << "moved to" << rect;
726 }
727 
timerEvent(QTimerEvent * event)728 void QQnxScreenEventHandler::timerEvent(QTimerEvent *event)
729 {
730     if (event->timerId() == m_focusLostTimer) {
731         killTimer(m_focusLostTimer);
732         m_focusLostTimer = -1;
733         event->accept();
734     } else {
735         QObject::timerEvent(event);
736     }
737 }
738 
739 #include "moc_qqnxscreeneventhandler.cpp"
740 
741 QT_END_NAMESPACE
742