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