1 /***************************************************************************
2 **
3 ** Copyright (C) 2011 - 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 "qqnxwindow.h"
43 #include "qqnxintegration.h"
44 #include "qqnxscreen.h"
45 #include "qqnxlgmon.h"
46 
47 #include <QUuid>
48 
49 #include <QtGui/QWindow>
50 #include <qpa/qwindowsysteminterface.h>
51 
52 #include "private/qguiapplication_p.h"
53 
54 #include <QtCore/QDebug>
55 
56 #include <errno.h>
57 
58 #if defined(QQNXWINDOW_DEBUG)
59 #define qWindowDebug qDebug
60 #else
61 #define qWindowDebug QT_NO_QDEBUG_MACRO
62 #endif
63 
64 QT_BEGIN_NAMESPACE
65 
66 #define DECLARE_DEBUG_VAR(variable) \
67     static bool debug_ ## variable() \
68     { static bool value = qgetenv("QNX_SCREEN_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(fps)69 DECLARE_DEBUG_VAR(fps)
70 DECLARE_DEBUG_VAR(posts)
71 DECLARE_DEBUG_VAR(blits)
72 DECLARE_DEBUG_VAR(updates)
73 DECLARE_DEBUG_VAR(cpu_time)
74 DECLARE_DEBUG_VAR(gpu_time)
75 DECLARE_DEBUG_VAR(statistics)
76 #undef DECLARE_DEBUG_VAR
77 
78 /*!
79     \class QQnxWindow
80     \brief The QQnxWindow is the base class of the various classes used as instances of
81     QPlatformWindow in the QNX QPA plugin.
82 
83     The standard properties and methods available in Qt are not a perfect match for the
84     features provided by the QNX screen service. While for the majority of applications
85     the default behavior suffices, some circumstances require greater control over the
86     interaction with screen.
87 
88     \section1 Window Types
89 
90     The QNX QPA plugin can operate in two modes, with or without a root window. The
91     selection of mode is made via the \e rootwindow and \e no-rootwindow options to the
92     plugin. The default mode is rootwindow for BlackBerry builds and no-rootwindow for
93     non-BlackBerry builds.
94 
95     Windows with parents are always created as child windows, the difference in the modes
96     is in the treatment of parentless windows. In no-rootwindow mode, these windows are
97     created as application windows while in rootwindow mode, the first window on a screen
98     is created as an application window while subsequent windows are created as child
99     windows. The only exception to this is any window of type Qt::Desktop or Qt::CoverWindow;
100     these are created as application windows, but will never become the root window,
101     even if they are the first window created.
102 
103     It is also possible to create a parentless child window. These may be useful to
104     create windows that are parented by windows from other processes. To do this, you
105     attach a dynamic property \e qnxInitialWindowGroup to the QWindow though this must be done
106     prior to the platform window class (this class) being created which typically happens
107     when the window is made visible. When the window is created in QML, it is acceptable
108     to have the \e visible property hardcoded to true so long as the qnxInitialWindowGroup
109     is also set.
110 
111     \section1 Joining Window Groups
112 
113     Window groups may be joined in a number of ways, some are automatic based on
114     predefined rules though an application is also able to provide explicit control.
115 
116     A QWindow that has a parent will join its parent's window group. When rootwindow mode
117     is in effect, all but the first parentless window on a screen will be child windows
118     and join the window group of the first parentless window, the root window.
119 
120     If a QWindow has a valid dynamic property called \e qnxInitialWindowGroup at the time the
121     QQnxWindow is created, the window will be created as a child window and, if the
122     qnxInitialWindowGroup property is a non-empty string, an attempt will be made to join that
123     window group. This has an effect only when the QQnxWindow is created, subsequent
124     changes to this property are ignored. Setting the property to an empty string
125     provides a means to create 'top level' child windows without automatically joining
126     any group. Typically when this property is used \e qnxWindowId should be used as well
127     so that the process that owns the window group being joined has some means to
128     identify the window.
129 
130     At any point following the creation of the QQnxWindow object, an application can
131     change the window group it has joined. This is done by using the \e
132     setWindowProperty function of the native interface to set the \e qnxWindowGroup property
133     to the desired value, for example:
134 
135     \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 0
136 
137     To leave the current window group, one passes a null value for the property value,
138     for example:
139 
140     \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 1
141 
142     \section1 Window Id
143 
144     The screen window id string property can be set on a window by assigning the desired
145     value to a dynamic property \e qnxWindowId on the QWindow prior to the QQnxWindow having
146     been created. This is often wanted when one joins a window group belonging to a
147     different process.
148 
149 */
150 QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow)
151     : QPlatformWindow(window),
152       m_screenContext(context),
153       m_window(0),
154       m_screen(0),
155       m_parentWindow(0),
156       m_visible(false),
157       m_exposed(true),
158       m_foreign(false),
159       m_windowState(Qt::WindowNoState),
160       m_mmRendererWindow(0),
161       m_firstActivateHandled(false)
162 {
163     qWindowDebug() << "window =" << window << ", size =" << window->size();
164 
165     QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window->screen()->handle());
166 
167     // If a qnxInitialWindowGroup property is set on the window we'll take this as an
168     // indication that we want to create a child window and join that window group.
169     QVariant windowGroup = window->property("qnxInitialWindowGroup");
170     if (!windowGroup.isValid())
171         windowGroup = window->property("_q_platform_qnxParentGroup");
172 
173     if (window->type() == Qt::CoverWindow) {
174         // Cover windows have to be top level to be accessible to window delegate (i.e. navigator)
175         // Desktop windows also need to be toplevel because they are not
176         // supposed to be part of the window hierarchy tree
177         m_isTopLevel = true;
178     } else if (parent() || windowGroup.isValid()) {
179         // If we have a parent we are a child window.  Sometimes we have to be a child even if we
180         // don't have a parent e.g. our parent might be in a different process.
181         m_isTopLevel = false;
182     } else {
183         // We're parentless.  If we're not using a root window, we'll always be a top-level window
184         // otherwise only the first window is.
185         m_isTopLevel = !needRootWindow || !platformScreen->rootWindow();
186     }
187 
188     if (window->type() == Qt::Desktop)  // A desktop widget does not need a libscreen window
189         return;
190 
191     QVariant type = window->property("_q_platform_qnxWindowType");
192     if (type.isValid() && type.canConvert<int>()) {
193         Q_SCREEN_CHECKERROR(
194                 screen_create_window_type(&m_window, m_screenContext, type.value<int>()),
195                 "Could not create window");
196     } else if (m_isTopLevel) {
197         Q_SCREEN_CRITICALERROR(screen_create_window(&m_window, m_screenContext),
198                             "Could not create top level window"); // Creates an application window
199         if (window->type() != Qt::CoverWindow) {
200             if (needRootWindow)
201                 platformScreen->setRootWindow(this);
202         }
203     } else {
204         Q_SCREEN_CHECKERROR(
205                 screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW),
206                 "Could not create child window");
207     }
208 
209     createWindowGroup();
210 
211     // If the window has a qnxWindowId property, set this as the string id property. This generally
212     // needs to be done prior to joining any group as it might be used by the owner of the
213     // group to identify the window.
214     QVariant windowId = window->property("qnxWindowId");
215     if (!windowId.isValid())
216         windowId = window->property("_q_platform_qnxWindowId");
217     if (windowId.isValid() && windowId.canConvert<QByteArray>()) {
218         QByteArray id = windowId.toByteArray();
219         Q_SCREEN_CHECKERROR(screen_set_window_property_cv(m_window, SCREEN_PROPERTY_ID_STRING,
220                             id.size(), id), "Failed to set id");
221     }
222 
223     // If a window group has been provided join it now. If it's an empty string that's OK too,
224     // it'll cause us not to join a group (the app will presumably join at some future time).
225     if (windowGroup.isValid() && windowGroup.canConvert<QByteArray>())
226         joinWindowGroup(windowGroup.toByteArray());
227 
228     QVariant pipelineValue = window->property("_q_platform_qnxPipeline");
229     if (pipelineValue.isValid()) {
230         bool ok = false;
231         int pipeline = pipelineValue.toInt(&ok);
232         if (ok) {
233             qWindowDebug() << "Set pipeline value to" << pipeline;
234 
235             Q_SCREEN_CHECKERROR(
236                 screen_set_window_property_iv(m_window, SCREEN_PROPERTY_PIPELINE, &pipeline),
237                 "Failed to set window pipeline");
238         } else {
239             qWindowDebug() << "Invalid pipeline value:" << pipelineValue;
240         }
241     }
242 
243     int debug = 0;
244     if (Q_UNLIKELY(debug_fps())) {
245         debug |= SCREEN_DEBUG_GRAPH_FPS;
246     }
247     if (Q_UNLIKELY(debug_posts())) {
248         debug |= SCREEN_DEBUG_GRAPH_POSTS;
249     }
250     if (Q_UNLIKELY(debug_blits())) {
251         debug |= SCREEN_DEBUG_GRAPH_BLITS;
252     }
253     if (Q_UNLIKELY(debug_updates())) {
254         debug |= SCREEN_DEBUG_GRAPH_UPDATES;
255     }
256     if (Q_UNLIKELY(debug_cpu_time())) {
257         debug |= SCREEN_DEBUG_GRAPH_CPU_TIME;
258     }
259     if (Q_UNLIKELY(debug_gpu_time())) {
260         debug |= SCREEN_DEBUG_GRAPH_GPU_TIME;
261     }
262     if (Q_UNLIKELY(debug_statistics())) {
263         debug = SCREEN_DEBUG_STATISTICS;
264     }
265 
266     if (debug > 0) {
267         Q_SCREEN_CHECKERROR(screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_DEBUG, &debug),
268                             "Could not set SCREEN_PROPERTY_DEBUG");
269         qWindowDebug() << "window SCREEN_PROPERTY_DEBUG= " << debug;
270     }
271 }
272 
QQnxWindow(QWindow * window,screen_context_t context,screen_window_t screenWindow)273 QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_t screenWindow)
274     : QPlatformWindow(window)
275     , m_screenContext(context)
276     , m_window(screenWindow)
277     , m_screen(0)
278     , m_parentWindow(0)
279     , m_visible(false)
280     , m_exposed(true)
281     , m_foreign(true)
282     , m_windowState(Qt::WindowNoState)
283     , m_mmRendererWindow(0)
284     , m_parentGroupName(256, 0)
285     , m_isTopLevel(false)
286 {
287     qWindowDebug() << "window =" << window << ", size =" << window->size();
288 
289     collectWindowGroup();
290 
291     screen_get_window_property_cv(m_window,
292                                   SCREEN_PROPERTY_PARENT,
293                                   m_parentGroupName.size(),
294                                   m_parentGroupName.data());
295     m_parentGroupName.resize(strlen(m_parentGroupName.constData()));
296 
297     // If a window group has been provided join it now. If it's an empty string that's OK too,
298     // it'll cause us not to join a group (the app will presumably join at some future time).
299     QVariant parentGroup = window->property("qnxInitialWindowGroup");
300     if (!parentGroup.isValid())
301         parentGroup = window->property("_q_platform_qnxParentGroup");
302     if (parentGroup.isValid() && parentGroup.canConvert<QByteArray>())
303         joinWindowGroup(parentGroup.toByteArray());
304 }
305 
~QQnxWindow()306 QQnxWindow::~QQnxWindow()
307 {
308     qWindowDebug() << "window =" << window();
309 
310     // Qt should have already deleted the children before deleting the parent.
311     Q_ASSERT(m_childWindows.size() == 0);
312 
313     // Remove from plugin's window mapper
314     QQnxIntegration::instance()->removeWindow(m_window);
315 
316     // Remove from parent's Hierarchy.
317     removeFromParent();
318     if (m_screen)
319         m_screen->updateHierarchy();
320 
321     // Cleanup QNX window and its buffers
322     // Foreign windows are cleaned up externally after the CLOSE event has been handled.
323     if (m_foreign)
324         removeContextPermission();
325     else
326         screen_destroy_window(m_window);
327 }
328 
setGeometry(const QRect & rect)329 void QQnxWindow::setGeometry(const QRect &rect)
330 {
331     QRect newGeometry = rect;
332     if (shouldMakeFullScreen())
333         newGeometry = screen()->geometry();
334 
335     if (window()->type() != Qt::Desktop)
336         setGeometryHelper(newGeometry);
337 
338     if (isExposed())
339         QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size()));
340 }
341 
setGeometryHelper(const QRect & rect)342 void QQnxWindow::setGeometryHelper(const QRect &rect)
343 {
344     qWindowDebug() << "window =" << window()
345                    << ", (" << rect.x() << "," << rect.y()
346                    << "," << rect.width() << "," << rect.height() << ")";
347 
348     // Call base class method
349     QPlatformWindow::setGeometry(rect);
350 
351     // Set window geometry equal to widget geometry
352     int val[2];
353     val[0] = rect.x();
354     val[1] = rect.y();
355     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val),
356                         "Failed to set window position");
357 
358     val[0] = rect.width();
359     val[1] = rect.height();
360     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val),
361                         "Failed to set window size");
362 
363     // Set viewport size equal to window size
364     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val),
365                         "Failed to set window source size");
366 
367     screen_flush_context(m_screenContext, 0);
368 
369     QWindowSystemInterface::handleGeometryChange(window(), rect);
370 }
371 
setVisible(bool visible)372 void QQnxWindow::setVisible(bool visible)
373 {
374     qWindowDebug() << "window =" << window() << "visible =" << visible;
375 
376     if (m_visible == visible || window()->type() == Qt::Desktop)
377         return;
378 
379     // The first time through we join a window group if appropriate.
380     if (m_parentGroupName.isNull() && !m_isTopLevel) {
381         joinWindowGroup(parent() ? static_cast<QQnxWindow*>(parent())->groupName()
382                                  : QByteArray(m_screen->windowGroupName()));
383     }
384 
385     m_visible = visible;
386 
387     QQnxWindow *root = this;
388     while (root->m_parentWindow)
389         root = root->m_parentWindow;
390 
391     root->updateVisibility(root->m_visible);
392 
393     QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size()));
394 
395     if (visible) {
396         applyWindowState();
397     } else {
398         if (showWithoutActivating() && focusable() && m_firstActivateHandled) {
399             m_firstActivateHandled = false;
400             int val = SCREEN_SENSITIVITY_NO_FOCUS;
401             Q_SCREEN_CHECKERROR(
402                 screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val),
403                 "Failed to set window sensitivity");
404         }
405 
406         // Flush the context, otherwise it won't disappear immediately
407         screen_flush_context(m_screenContext, 0);
408     }
409 }
410 
updateVisibility(bool parentVisible)411 void QQnxWindow::updateVisibility(bool parentVisible)
412 {
413     qWindowDebug() << "parentVisible =" << parentVisible << "window =" << window();
414     // Set window visibility
415     int val = (m_visible && parentVisible) ? 1 : 0;
416     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val),
417                         "Failed to set window visibility");
418 
419     Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
420         childWindow->updateVisibility(m_visible && parentVisible);
421 }
422 
setOpacity(qreal level)423 void QQnxWindow::setOpacity(qreal level)
424 {
425     qWindowDebug() << "window =" << window() << "opacity =" << level;
426     // Set window global alpha
427     int val = (int)(level * 255);
428     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val),
429                         "Failed to set global alpha");
430 
431     screen_flush_context(m_screenContext, 0);
432 }
433 
setExposed(bool exposed)434 void QQnxWindow::setExposed(bool exposed)
435 {
436     qWindowDebug() << "window =" << window() << "expose =" << exposed;
437 
438     if (m_exposed != exposed) {
439         m_exposed = exposed;
440         QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size()));
441     }
442 }
443 
isExposed() const444 bool QQnxWindow::isExposed() const
445 {
446     return m_visible && m_exposed;
447 }
448 
setBufferSize(const QSize & size)449 void QQnxWindow::setBufferSize(const QSize &size)
450 {
451     qWindowDebug() << "window =" << window() << "size =" << size;
452 
453     // libscreen fails when creating empty buffers
454     const QSize nonEmptySize = size.isEmpty() ? QSize(1, 1) : size;
455     int format = pixelFormat();
456 
457     if (nonEmptySize == m_bufferSize || format == -1)
458         return;
459 
460     Q_SCREEN_CRITICALERROR(
461             screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, &format),
462             "Failed to set window format");
463 
464     if (m_bufferSize.isValid()) {
465         // destroy buffers first, if resized
466         Q_SCREEN_CRITICALERROR(screen_destroy_window_buffers(m_window),
467                                "Failed to destroy window buffers");
468     }
469 
470     int val[2] = { nonEmptySize.width(), nonEmptySize.height() };
471     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val),
472                         "Failed to set window buffer size");
473 
474     Q_SCREEN_CRITICALERROR(screen_create_window_buffers(m_window, MAX_BUFFER_COUNT),
475                            "Failed to create window buffers");
476 
477     // check if there are any buffers available
478     int bufferCount = 0;
479     Q_SCREEN_CRITICALERROR(
480         screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount),
481         "Failed to query render buffer count");
482 
483     if (Q_UNLIKELY(bufferCount != MAX_BUFFER_COUNT)) {
484         qFatal("QQnxWindow: invalid buffer count. Expected = %d, got = %d.",
485                 MAX_BUFFER_COUNT, bufferCount);
486     }
487 
488     // Set the transparency. According to QNX technical support, setting the window
489     // transparency property should always be done *after* creating the window
490     // buffers in order to guarantee the property is paid attention to.
491     if (size.isEmpty()) {
492         // We can't create 0x0 buffers and instead make them 1x1.  But to allow these windows to
493         // still be 'visible' (thus allowing their children to be visible), we need to allow
494         // them to be posted but still not show up.
495         val[0] = SCREEN_TRANSPARENCY_DISCARD;
496     } else if (window()->requestedFormat().alphaBufferSize() == 0) {
497         // To avoid overhead in the composition manager, disable blending
498         // when the underlying window buffer doesn't have an alpha channel.
499         val[0] = SCREEN_TRANSPARENCY_NONE;
500     } else {
501         // Normal alpha blending. This doesn't commit us to translucency; the
502         // normal backfill during the painting will contain a fully opaque
503         // alpha channel unless the user explicitly intervenes to make something
504         // transparent.
505         val[0] = SCREEN_TRANSPARENCY_SOURCE_OVER;
506     }
507 
508     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val),
509                         "Failed to set window transparency");
510 
511     // Cache new buffer size
512     m_bufferSize = nonEmptySize;
513     resetBuffers();
514 }
515 
setScreen(QQnxScreen * platformScreen)516 void QQnxWindow::setScreen(QQnxScreen *platformScreen)
517 {
518     qWindowDebug() << "window =" << window() << "platformScreen =" << platformScreen;
519 
520     if (platformScreen == 0) { // The screen has been destroyed
521         m_screen = 0;
522         Q_FOREACH (QQnxWindow *childWindow, m_childWindows) {
523             childWindow->setScreen(0);
524         }
525         return;
526     }
527 
528     if (m_screen == platformScreen)
529         return;
530 
531     if (m_screen) {
532         qWindowDebug("Moving window to different screen");
533         m_screen->removeWindow(this);
534 
535         if ((QQnxIntegration::instance()->options() & QQnxIntegration::RootWindow)) {
536             screen_leave_window_group(m_window);
537         }
538     }
539 
540     m_screen = platformScreen;
541     if (!m_parentWindow) {
542         platformScreen->addWindow(this);
543     }
544     if (m_isTopLevel) {
545         // Move window to proper screen/display
546         screen_display_t display = platformScreen->nativeDisplay();
547         Q_SCREEN_CHECKERROR(
548                screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display),
549                "Failed to set window display");
550     } else {
551         Q_FOREACH (QQnxWindow *childWindow, m_childWindows) {
552             // Only subwindows and tooltips need necessarily be moved to another display with the window.
553             if (window()->type() == Qt::SubWindow || window()->type() == Qt::ToolTip)
554                 childWindow->setScreen(platformScreen);
555         }
556     }
557 
558     m_screen->updateHierarchy();
559 }
560 
removeFromParent()561 void QQnxWindow::removeFromParent()
562 {
563     qWindowDebug() << "window =" << window();
564     // Remove from old Hierarchy position
565     if (m_parentWindow) {
566         if (Q_UNLIKELY(!m_parentWindow->m_childWindows.removeAll(this)))
567             qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
568         else
569             m_parentWindow = 0;
570     } else if (m_screen) {
571         m_screen->removeWindow(this);
572     }
573 }
574 
setParent(const QPlatformWindow * window)575 void QQnxWindow::setParent(const QPlatformWindow *window)
576 {
577     qWindowDebug() << "window =" << this->window() << "platformWindow =" << window;
578     // Cast away the const, we need to modify the hierarchy.
579     QQnxWindow* const newParent = static_cast<QQnxWindow*>(const_cast<QPlatformWindow*>(window));
580 
581     if (newParent == m_parentWindow)
582         return;
583 
584     if (static_cast<QQnxScreen *>(screen())->rootWindow() == this) {
585         qWarning("Application window cannot be reparented");
586         return;
587     }
588 
589     removeFromParent();
590     m_parentWindow = newParent;
591 
592     // Add to new hierarchy position.
593     if (m_parentWindow) {
594         if (m_parentWindow->m_screen != m_screen)
595             setScreen(m_parentWindow->m_screen);
596 
597         m_parentWindow->m_childWindows.push_back(this);
598         joinWindowGroup(m_parentWindow->groupName());
599     } else {
600         m_screen->addWindow(this);
601         joinWindowGroup(QByteArray());
602     }
603 
604     m_screen->updateHierarchy();
605 }
606 
raise()607 void QQnxWindow::raise()
608 {
609     qWindowDebug() << "window =" << window();
610 
611     if (m_parentWindow) {
612         m_parentWindow->m_childWindows.removeAll(this);
613         m_parentWindow->m_childWindows.push_back(this);
614     } else {
615         m_screen->raiseWindow(this);
616     }
617 
618     m_screen->updateHierarchy();
619 }
620 
lower()621 void QQnxWindow::lower()
622 {
623     qWindowDebug() << "window =" << window();
624 
625     if (m_parentWindow) {
626         m_parentWindow->m_childWindows.removeAll(this);
627         m_parentWindow->m_childWindows.push_front(this);
628     } else {
629         m_screen->lowerWindow(this);
630     }
631 
632     m_screen->updateHierarchy();
633 }
634 
requestActivateWindow()635 void QQnxWindow::requestActivateWindow()
636 {
637     QQnxWindow *focusWindow = 0;
638     if (QGuiApplication::focusWindow())
639         focusWindow = static_cast<QQnxWindow*>(QGuiApplication::focusWindow()->handle());
640 
641     if (focusWindow == this)
642         return;
643 
644     if (static_cast<QQnxScreen *>(screen())->rootWindow() == this ||
645             (focusWindow && findWindow(focusWindow->nativeHandle()))) {
646         // If the focus window is a child, we can just set the focus of our own window
647         // group to our window handle
648         setFocus(nativeHandle());
649     } else {
650         // In order to receive focus the parent's window group has to give focus to the
651         // child. If we have several hierarchy layers, we have to do that several times
652         QQnxWindow *currentWindow = this;
653         QList<QQnxWindow*> windowList;
654         while (currentWindow) {
655             auto platformScreen = static_cast<QQnxScreen *>(screen());
656             windowList.prepend(currentWindow);
657             // If we find the focus window, we don't have to go further
658             if (currentWindow == focusWindow)
659                 break;
660 
661             if (currentWindow->parent()){
662                 currentWindow = static_cast<QQnxWindow*>(currentWindow->parent());
663             } else if (platformScreen->rootWindow() &&
664                   platformScreen->rootWindow()->m_windowGroupName == currentWindow->m_parentGroupName) {
665                 currentWindow = platformScreen->rootWindow();
666             } else {
667                 currentWindow = 0;
668             }
669         }
670 
671         // We have to apply the focus from parent to child windows
672         for (int i = 1; i < windowList.size(); ++i)
673             windowList.at(i-1)->setFocus(windowList.at(i)->nativeHandle());
674 
675         windowList.last()->setFocus(windowList.constLast()->nativeHandle());
676     }
677 
678     screen_flush_context(m_screenContext, 0);
679 }
680 
setFocus(screen_window_t newFocusWindow)681 void QQnxWindow::setFocus(screen_window_t newFocusWindow)
682 {
683     screen_window_t temporaryFocusWindow = nullptr;
684 
685     screen_group_t screenGroup = 0;
686     Q_SCREEN_CHECKERROR(screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_GROUP,
687                                                       reinterpret_cast<void **>(&screenGroup)),
688                         "Failed to retrieve window group");
689 
690     if (showWithoutActivating() && focusable() && !m_firstActivateHandled) {
691         m_firstActivateHandled = true;
692         int val = SCREEN_SENSITIVITY_TEST;
693         Q_SCREEN_CHECKERROR(
694             screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val),
695             "Failed to set window sensitivity");
696 
697 #if _SCREEN_VERSION < _SCREEN_MAKE_VERSION(1, 0, 0)
698         // For older versions of screen, the window may still have group
699         // focus even though it was marked NO_FOCUS when it was hidden.
700         // In that situation, focus has to be given to another window
701         // so that this window can take focus back from it.
702         screen_window_t oldFocusWindow = nullptr;
703         Q_SCREEN_CHECKERROR(
704             screen_get_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS,
705                                          reinterpret_cast<void **>(&oldFocusWindow)),
706             "Failed to retrieve group focus");
707         if (newFocusWindow == oldFocusWindow) {
708             char groupName[256];
709             memset(groupName, 0, sizeof(groupName));
710             Q_SCREEN_CHECKERROR(screen_get_group_property_cv(screenGroup, SCREEN_PROPERTY_NAME,
711                                                              sizeof(groupName) - 1, groupName),
712                                 "Failed to retrieve group name");
713 
714             Q_SCREEN_CHECKERROR(screen_create_window_type(&temporaryFocusWindow,
715                                                           m_screenContext, SCREEN_CHILD_WINDOW),
716                                 "Failed to create temporary focus window");
717             Q_SCREEN_CHECKERROR(screen_join_window_group(temporaryFocusWindow, groupName),
718                                 "Temporary focus window failed to join window group");
719             Q_SCREEN_CHECKERROR(
720                 screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS,
721                                              reinterpret_cast<void **>(&temporaryFocusWindow)),
722                 "Temporary focus window failed to take focus");
723             screen_flush_context(m_screenContext, 0);
724         }
725 #endif
726     }
727 
728     Q_SCREEN_CHECKERROR(screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_FOCUS,
729                                                      reinterpret_cast<void **>(&newFocusWindow)),
730                         "Failed to set group focus");
731 
732     screen_destroy_window(temporaryFocusWindow);
733 }
734 
setWindowState(Qt::WindowStates state)735 void QQnxWindow::setWindowState(Qt::WindowStates state)
736 {
737     qWindowDebug() << "state =" << state;
738 
739     // Prevent two calls with Qt::WindowFullScreen from changing m_unmaximizedGeometry
740     if (m_windowState == state)
741         return;
742 
743     m_windowState = state;
744 
745     if (m_visible)
746         applyWindowState();
747 }
748 
propagateSizeHints()749 void QQnxWindow::propagateSizeHints()
750 {
751     // nothing to do; silence base class warning
752     qWindowDebug("ignored");
753 }
754 
setMMRendererWindowName(const QString & name)755 void QQnxWindow::setMMRendererWindowName(const QString &name)
756 {
757     m_mmRendererWindowName = name;
758 }
759 
setMMRendererWindow(screen_window_t handle)760 void QQnxWindow::setMMRendererWindow(screen_window_t handle)
761 {
762     m_mmRendererWindow = handle;
763 }
764 
clearMMRendererWindow()765 void QQnxWindow::clearMMRendererWindow()
766 {
767     m_mmRendererWindowName.clear();
768     m_mmRendererWindow = 0;
769 }
770 
screen() const771 QPlatformScreen *QQnxWindow::screen() const
772 {
773     return m_screen;
774 }
775 
findWindow(screen_window_t windowHandle)776 QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle)
777 {
778     if (m_window == windowHandle)
779         return this;
780 
781     Q_FOREACH (QQnxWindow *window, m_childWindows) {
782         QQnxWindow * const result = window->findWindow(windowHandle);
783         if (result)
784             return result;
785     }
786 
787     return 0;
788 }
789 
minimize()790 void QQnxWindow::minimize()
791 {
792     qWarning("Qt::WindowMinimized is not supported by this OS version");
793 }
794 
setRotation(int rotation)795 void QQnxWindow::setRotation(int rotation)
796 {
797     qWindowDebug() << "angle =" << rotation;
798     Q_SCREEN_CHECKERROR(
799             screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation),
800             "Failed to set window rotation");
801 }
802 
initWindow()803 void QQnxWindow::initWindow()
804 {
805     if (window()->type() == Qt::Desktop)
806         return;
807 
808     // Alpha channel is always pre-multiplied if present
809     int val = SCREEN_PRE_MULTIPLIED_ALPHA;
810     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val),
811                         "Failed to set alpha mode");
812 
813     // Set the window swap interval
814     val = 1;
815     Q_SCREEN_CHECKERROR(
816             screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val),
817             "Failed to set swap interval");
818 
819     if (showWithoutActivating() || !focusable()) {
820         // NO_FOCUS is temporary for showWithoutActivating (and pop-up) windows.
821         // Using NO_FOCUS ensures that screen doesn't activate the window because
822         // it was just created.  Sensitivity will be changed to TEST when the
823         // window is clicked or touched.
824         val = SCREEN_SENSITIVITY_NO_FOCUS;
825         Q_SCREEN_CHECKERROR(
826                 screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val),
827                 "Failed to set window sensitivity");
828     }
829 
830     QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window()->screen()->handle());
831     setScreen(platformScreen);
832 
833     if (window()->type() == Qt::CoverWindow)
834         m_exposed = false;
835 
836     // Add window to plugin's window mapper
837     QQnxIntegration::instance()->addWindow(m_window, window());
838 
839     // Qt never calls these setters after creating the window, so we need to do that ourselves here
840     setWindowState(window()->windowState());
841     setOpacity(window()->opacity());
842 
843     if (window()->parent() && window()->parent()->handle())
844         setParent(window()->parent()->handle());
845 
846     setGeometryHelper(shouldMakeFullScreen() ? screen()->geometry() : window()->geometry());
847 }
848 
collectWindowGroup()849 void QQnxWindow::collectWindowGroup()
850 {
851     QByteArray groupName(256, 0);
852     Q_SCREEN_CHECKERROR(screen_get_window_property_cv(m_window,
853                                                       SCREEN_PROPERTY_GROUP,
854                                                       groupName.size(),
855                                                       groupName.data()),
856                         "Failed to retrieve window group");
857     groupName.resize(strlen(groupName.constData()));
858     m_windowGroupName = groupName;
859 }
860 
createWindowGroup()861 void QQnxWindow::createWindowGroup()
862 {
863     Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, nullptr),
864                         "Failed to create window group");
865 
866     collectWindowGroup();
867 }
868 
joinWindowGroup(const QByteArray & groupName)869 void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
870 {
871     bool changed = false;
872 
873     qWindowDebug() << "group:" << groupName;
874 
875     // screen has this annoying habit of generating a CLOSE/CREATE when the owner context of
876     // the parent group moves a foreign window to another group that it also owns.  The
877     // CLOSE/CREATE changes the identity of the foreign window.  Usually, this is undesirable.
878     // To prevent this CLOSE/CREATE when changing the parent group, we temporarily add a
879     // context permission for the Qt context.  screen won't send a CLOSE/CREATE when the
880     // context has some permission other than the PARENT permission.  If there isn't a new
881     // group (the window has no parent), this context permission is left in place.
882 
883     if (m_foreign && !m_parentGroupName.isEmpty())\
884         addContextPermission();
885 
886     if (!groupName.isEmpty()) {
887         if (groupName != m_parentGroupName) {
888             screen_join_window_group(m_window, groupName);
889             m_parentGroupName = groupName;
890             changed = true;
891         }
892     } else {
893         if (!m_parentGroupName.isEmpty()) {
894             screen_leave_window_group(m_window);
895             changed = true;
896         }
897         // By setting to an empty string we'll stop setVisible from trying to
898         // change our group, we want that to happen only if joinWindowGroup has
899         // never been called.  This allows windows to be created that are not initially
900         // part of any group.
901         m_parentGroupName = "";
902     }
903 
904     if (m_foreign && !groupName.isEmpty())
905         removeContextPermission();
906 
907     if (changed)
908         screen_flush_context(m_screenContext, 0);
909 }
910 
updateZorder(int & topZorder)911 void QQnxWindow::updateZorder(int &topZorder)
912 {
913     updateZorder(m_window, topZorder);
914 
915     if (m_mmRendererWindow)
916         updateZorder(m_mmRendererWindow, topZorder);
917 
918     Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
919         childWindow->updateZorder(topZorder);
920 }
921 
updateZorder(screen_window_t window,int & topZorder)922 void QQnxWindow::updateZorder(screen_window_t window, int &topZorder)
923 {
924     Q_SCREEN_CHECKERROR(screen_set_window_property_iv(window, SCREEN_PROPERTY_ZORDER, &topZorder),
925                         "Failed to set window z-order");
926     topZorder++;
927 }
928 
applyWindowState()929 void QQnxWindow::applyWindowState()
930 {
931     if (m_windowState & Qt::WindowMinimized) {
932         minimize();
933 
934         if (m_unmaximizedGeometry.isValid())
935             setGeometry(m_unmaximizedGeometry);
936         else
937             setGeometry(m_screen->geometry());
938     } else if (m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen)) {
939         m_unmaximizedGeometry = geometry();
940         setGeometry(m_windowState & Qt::WindowFullScreen ? m_screen->geometry()
941                                                          : m_screen->availableGeometry());
942     } else if (m_unmaximizedGeometry.isValid()) {
943         setGeometry(m_unmaximizedGeometry);
944     }
945 }
946 
windowPosted()947 void QQnxWindow::windowPosted()
948 {
949     if (m_cover)
950         m_cover->updateCover();
951 
952     qqnxLgmonFramePosted(m_cover);  // for performance measurements
953 }
954 
shouldMakeFullScreen() const955 bool QQnxWindow::shouldMakeFullScreen() const
956 {
957     return ((static_cast<QQnxScreen *>(screen())->rootWindow() == this)
958             && (QQnxIntegration::instance()->options() & QQnxIntegration::FullScreenApplication));
959 }
960 
961 
handleActivationEvent()962 void QQnxWindow::handleActivationEvent()
963 {
964     if (showWithoutActivating() && focusable() && !m_firstActivateHandled)
965         requestActivateWindow();
966 }
967 
showWithoutActivating() const968 bool QQnxWindow::showWithoutActivating() const
969 {
970     return (window()->flags() & Qt::Popup) == Qt::Popup
971         || window()->property("_q_showWithoutActivating").toBool();
972 }
973 
focusable() const974 bool QQnxWindow::focusable() const
975 {
976     return (window()->flags() & Qt::WindowDoesNotAcceptFocus) != Qt::WindowDoesNotAcceptFocus;
977 }
978 
addContextPermission()979 void QQnxWindow::addContextPermission()
980 {
981     QByteArray grantString("context:");
982     grantString.append(QQnxIntegration::instance()->screenContextId());
983     grantString.append(":rw-");
984     screen_set_window_property_cv(m_window,
985             SCREEN_PROPERTY_PERMISSIONS,
986             grantString.length(),
987             grantString.data());
988 }
989 
removeContextPermission()990 void QQnxWindow::removeContextPermission()
991 {
992     QByteArray revokeString("context:");
993     revokeString.append(QQnxIntegration::instance()->screenContextId());
994     revokeString.append(":---");
995     screen_set_window_property_cv(m_window,
996             SCREEN_PROPERTY_PERMISSIONS,
997             revokeString.length(),
998             revokeString.data());
999 }
1000 
1001 QT_END_NAMESPACE
1002