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