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