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