blob: 46df500330e78b3a67f4a339a1037172db0ec2b0 [file] [log] [blame]
/***************************************************************************
**
** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qqnxglobal.h"
#include "qqnxscreen.h"
#include "qqnxwindow.h"
#include "qqnxcursor.h"
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <qpa/qwindowsysteminterface.h>
#include <errno.h>
#if defined(QQNXSCREEN_DEBUG)
#define qScreenDebug qDebug
#else
#define qScreenDebug QT_NO_QDEBUG_MACRO
#endif
#if defined(QQNX_PHYSICAL_SCREEN_WIDTH) && QQNX_PHYSICAL_SCREEN_WIDTH > 0 \
&& defined(QQNX_PHYSICAL_SCREEN_HEIGHT) && QQNX_PHYSICAL_SCREEN_HEIGHT > 0
#define QQNX_PHYSICAL_SCREEN_SIZE_DEFINED
#elif defined(QQNX_PHYSICAL_SCREEN_WIDTH) || defined(QQNX_PHYSICAL_SCREEN_HEIGHT)
#error Please define QQNX_PHYSICAL_SCREEN_WIDTH and QQNX_PHYSICAL_SCREEN_HEIGHT to values greater than zero
#endif
// The default z-order of a window (intended to be overlain) created by
// mmrender.
static const int MMRENDER_DEFAULT_ZORDER = -1;
// The maximum z-order at which a foreign window will be considered
// an underlay.
static const int MAX_UNDERLAY_ZORDER = MMRENDER_DEFAULT_ZORDER - 1;
QT_BEGIN_NAMESPACE
static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
int val[2];
const int result = screen_get_display_property_iv(display, SCREEN_PROPERTY_PHYSICAL_SIZE, val);
Q_SCREEN_CHECKERROR(result, "Failed to query display physical size");
if (result != 0) {
return QSize(150, 90);
}
if (val[0] > 0 && val[1] > 0)
return QSize(val[0], val[1]);
qScreenDebug("QQnxScreen: screen_get_display_property_iv() reported an invalid "
"physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE "
"environment variable.", val[0], val[1]);
const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE");
if (!envPhySizeStr.isEmpty()) {
const auto envPhySizeStrList = envPhySizeStr.splitRef(QLatin1Char(','));
const int envWidth = envPhySizeStrList.size() == 2 ? envPhySizeStrList[0].toInt() : -1;
const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1;
if (envWidth <= 0 || envHeight <= 0) {
qWarning("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format "
"\"width,height\" in mm, with width, height > 0. Defaulting to 150x90. "
"Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90");
return QSize(150, 90);
}
return QSize(envWidth, envHeight);
}
#if defined(QQNX_PHYSICAL_SCREEN_SIZE_DEFINED)
const QSize defSize(QQNX_PHYSICAL_SCREEN_WIDTH, QQNX_PHYSICAL_SCREEN_HEIGHT);
qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Falling back to defines "
"QQNX_PHYSICAL_SCREEN_WIDTH/QQNX_PHYSICAL_SCREEN_HEIGHT (%dx%d)",
defSize.width(), defSize.height());
return defSize;
#else
if (primaryScreen)
qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. "
"Could not determine physical screen size. Defaulting to 150x90.");
return QSize(150, 90);
#endif
}
static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> &windows,
const QByteArray &mmWindowId)
{
Q_FOREACH (QQnxWindow *sibling, windows) {
if (sibling->mmRendererWindowName() == mmWindowId)
return sibling;
QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
if (mmWindow)
return mmWindow;
}
return 0;
}
static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> &windows,
screen_window_t mmWindowId)
{
Q_FOREACH (QQnxWindow *sibling, windows) {
if (sibling->mmRendererWindow() == mmWindowId)
return sibling;
QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
if (mmWindow)
return mmWindow;
}
return 0;
}
QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
: m_screenContext(screenContext),
m_display(display),
m_rootWindow(0),
m_primaryScreen(primaryScreen),
m_keyboardHeight(0),
m_nativeOrientation(Qt::PrimaryOrientation),
m_coverWindow(0),
m_cursor(new QQnxCursor())
{
qScreenDebug();
// Cache initial orientation of this display
int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION,
&m_initialRotation);
Q_SCREEN_CHECKERROR(result, "Failed to query display rotation");
m_currentRotation = m_initialRotation;
// Cache size of this display in pixels
int val[2];
Q_SCREEN_CRITICALERROR(screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val),
"Failed to query display size");
m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
char name[100];
Q_SCREEN_CHECKERROR(screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, 100,
name), "Failed to query display name");
m_name = QString::fromUtf8(name);
// Cache size of this display in millimeters. We have to take care of the orientation.
// libscreen always reports the physical size dimensions as width and height in the
// native orientation. Contrary to this, QPlatformScreen::physicalSize() expects the
// returned dimensions to follow the current orientation.
const QSize screenSize = determineScreenSize(m_display, primaryScreen);
m_nativeOrientation = screenSize.width() >= screenSize.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
const int angle = screen()->angleBetween(m_nativeOrientation, orientation());
if (angle == 0 || angle == 180)
m_currentPhysicalSize = m_initialPhysicalSize = screenSize;
else
m_currentPhysicalSize = m_initialPhysicalSize = screenSize.transposed();
}
QQnxScreen::~QQnxScreen()
{
qScreenDebug();
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setScreen(0);
if (m_coverWindow)
m_coverWindow->setScreen(0);
delete m_cursor;
}
QPixmap QQnxScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
QQnxWindow *qnxWin = findWindow(reinterpret_cast<screen_window_t>(window));
if (!qnxWin) {
qWarning("grabWindow: unknown window");
return QPixmap();
}
QRect bound = qnxWin->geometry();
if (width < 0)
width = bound.width();
if (height < 0)
height = bound.height();
bound &= QRect(x + bound.x(), y + bound.y(), width, height);
if (bound.width() <= 0 || bound.height() <= 0) {
qWarning("grabWindow: size is null");
return QPixmap();
}
// Create new context, only SCREEN_DISPLAY_MANAGER_CONTEXT can read from screen
screen_context_t context;
if (screen_create_context(&context, SCREEN_DISPLAY_MANAGER_CONTEXT)) {
if (errno == EPERM)
qWarning("grabWindow: root privileges required");
else
qWarning("grabWindow: cannot create context");
return QPixmap();
}
// Find corresponding display in SCREEN_DISPLAY_MANAGER_CONTEXT
int count = 0;
screen_display_t display = 0;
screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &count);
if (count > 0) {
const size_t idLen = 30;
char matchId[idLen];
char id[idLen];
bool found = false;
screen_display_t *displays = static_cast<screen_display_t*>
(calloc(count, sizeof(screen_display_t)));
screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, idLen, matchId);
while (count && !found) {
--count;
screen_get_display_property_cv(displays[count], SCREEN_PROPERTY_ID_STRING, idLen, id);
found = !strncmp(id, matchId, idLen);
}
if (found)
display = displays[count];
free(displays);
}
// Create screen and Qt pixmap
screen_pixmap_t pixmap;
QPixmap result;
if (display && !screen_create_pixmap(&pixmap, context)) {
screen_buffer_t buffer;
void *pointer;
int stride;
const int rect[4] = { bound.x(), bound.y(), bound.width(), bound.height() };
int val = SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE;
screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_USAGE, &val);
val = SCREEN_FORMAT_RGBA8888;
screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_FORMAT, &val);
int err = screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
err = err || screen_create_pixmap_buffer(pixmap);
err = err || screen_get_pixmap_property_pv(pixmap, SCREEN_PROPERTY_RENDER_BUFFERS,
reinterpret_cast<void**>(&buffer));
err = err || screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &pointer);
err = err || screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride);
err = err || screen_read_display(display, buffer, 1, rect, 0);
if (!err) {
const QImage img(static_cast<unsigned char*>(pointer),
bound.width(), bound.height(), stride, QImage::Format_ARGB32);
result = QPixmap::fromImage(img);
} else {
qWarning("grabWindow: capture error");
}
screen_destroy_pixmap(pixmap);
} else {
qWarning("grabWindow: display/pixmap error ");
}
screen_destroy_context(context);
return result;
}
static int defaultDepth()
{
qScreenDebug();
static int defaultDepth = 0;
if (defaultDepth == 0) {
// check if display depth was specified in environment variable;
// use default value if no valid value found
defaultDepth = qEnvironmentVariableIntValue("QQNX_DISPLAY_DEPTH");
if (defaultDepth != 16 && defaultDepth != 32)
defaultDepth = 32;
}
return defaultDepth;
}
QRect QQnxScreen::availableGeometry() const
{
qScreenDebug();
// available geometry = total geometry - keyboard
return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
m_currentGeometry.width(), m_currentGeometry.height() - m_keyboardHeight);
}
int QQnxScreen::depth() const
{
return defaultDepth();
}
qreal QQnxScreen::refreshRate() const
{
screen_display_mode_t displayMode;
int result = screen_get_display_property_pv(m_display, SCREEN_PROPERTY_MODE, reinterpret_cast<void **>(&displayMode));
// Screen shouldn't really return 0 but it does so default to 60 or things break.
if (result != 0 || displayMode.refresh == 0) {
qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
return 60.0;
}
qScreenDebug("screen mode:\n"
" width = %u\n"
" height = %u\n"
" refresh = %u\n"
" interlaced = %u",
uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
return static_cast<qreal>(displayMode.refresh);
}
Qt::ScreenOrientation QQnxScreen::nativeOrientation() const
{
return m_nativeOrientation;
}
Qt::ScreenOrientation QQnxScreen::orientation() const
{
Qt::ScreenOrientation orient;
if (m_nativeOrientation == Qt::LandscapeOrientation) {
// Landscape devices e.g. PlayBook
if (m_currentRotation == 0)
orient = Qt::LandscapeOrientation;
else if (m_currentRotation == 90)
orient = Qt::PortraitOrientation;
else if (m_currentRotation == 180)
orient = Qt::InvertedLandscapeOrientation;
else
orient = Qt::InvertedPortraitOrientation;
} else {
// Portrait devices e.g. Phones
// ###TODO Check these on an actual phone device
if (m_currentRotation == 0)
orient = Qt::PortraitOrientation;
else if (m_currentRotation == 90)
orient = Qt::LandscapeOrientation;
else if (m_currentRotation == 180)
orient = Qt::InvertedPortraitOrientation;
else
orient = Qt::InvertedLandscapeOrientation;
}
qScreenDebug() << "orientation =" << orient;
return orient;
}
QWindow *QQnxScreen::topLevelAt(const QPoint &point) const
{
for (auto it = m_childWindows.rbegin(), end = m_childWindows.rend(); it != end; ++it) {
QWindow *win = (*it)->window();
if (win->geometry().contains(point))
return win;
}
return 0;
}
/*!
Check if the supplied angles are perpendicular to each other.
*/
static bool isOrthogonal(int angle1, int angle2)
{
return ((angle1 - angle2) % 180) != 0;
}
void QQnxScreen::setRotation(int rotation)
{
qScreenDebug("orientation = %d", rotation);
// Check if rotation changed
// We only want to rotate if we are the primary screen
if (m_currentRotation != rotation && isPrimaryScreen()) {
// Update rotation of root window
if (rootWindow())
rootWindow()->setRotation(rotation);
const QRect previousScreenGeometry = geometry();
// Swap dimensions if we've rotated 90 or 270 from initial orientation
if (isOrthogonal(m_initialRotation, rotation)) {
m_currentGeometry = QRect(0, 0, m_initialGeometry.height(), m_initialGeometry.width());
m_currentPhysicalSize = QSize(m_initialPhysicalSize.height(), m_initialPhysicalSize.width());
} else {
m_currentGeometry = QRect(0, 0, m_initialGeometry.width(), m_initialGeometry.height());
m_currentPhysicalSize = m_initialPhysicalSize;
}
// Resize root window if we've rotated 90 or 270 from previous orientation
if (isOrthogonal(m_currentRotation, rotation)) {
qScreenDebug() << "resize, size =" << m_currentGeometry.size();
if (rootWindow())
rootWindow()->setGeometry(QRect(QPoint(0,0), m_currentGeometry.size()));
resizeWindows(previousScreenGeometry);
} else {
// TODO: Find one global place to flush display updates
// Force immediate display update if no geometry changes required
screen_flush_context(nativeContext(), 0);
}
// Save new rotation
m_currentRotation = rotation;
// TODO: check if other screens are supposed to rotate as well and/or whether this depends
// on if clone mode is being used.
// Rotating only the primary screen is what we had in the navigator event handler before refactoring
if (m_primaryScreen) {
QWindowSystemInterface::handleScreenOrientationChange(screen(), orientation());
QWindowSystemInterface::handleScreenGeometryChange(screen(), m_currentGeometry, availableGeometry());
}
// Flush everything, so that the windows rotations are applied properly.
// Needed for non-maximized windows
screen_flush_context( m_screenContext, 0 );
}
}
/*!
Resize the given window proportionally to the screen geometry
*/
void QQnxScreen::resizeNativeWidgetWindow(QQnxWindow *w, const QRect &previousScreenGeometry) const
{
const qreal relativeX = static_cast<qreal>(w->geometry().topLeft().x()) / previousScreenGeometry.width();
const qreal relativeY = static_cast<qreal>(w->geometry().topLeft().y()) / previousScreenGeometry.height();
const qreal relativeWidth = static_cast<qreal>(w->geometry().width()) / previousScreenGeometry.width();
const qreal relativeHeight = static_cast<qreal>(w->geometry().height()) / previousScreenGeometry.height();
const QRect windowGeometry(relativeX * geometry().width(), relativeY * geometry().height(),
relativeWidth * geometry().width(), relativeHeight * geometry().height());
w->setGeometry(windowGeometry);
}
/*!
Resize the given window to fit the screen geometry
*/
void QQnxScreen::resizeTopLevelWindow(QQnxWindow *w, const QRect &previousScreenGeometry) const
{
QRect windowGeometry = w->geometry();
const qreal relativeCenterX = static_cast<qreal>(w->geometry().center().x()) / previousScreenGeometry.width();
const qreal relativeCenterY = static_cast<qreal>(w->geometry().center().y()) / previousScreenGeometry.height();
const QPoint newCenter(relativeCenterX * geometry().width(), relativeCenterY * geometry().height());
windowGeometry.moveCenter(newCenter);
// adjust center position in case the window
// is clipped
if (!geometry().contains(windowGeometry)) {
const int x1 = windowGeometry.x();
const int y1 = windowGeometry.y();
const int x2 = x1 + windowGeometry.width();
const int y2 = y1 + windowGeometry.height();
if (x1 < 0) {
const int centerX = qMin(qAbs(x1) + windowGeometry.center().x(),
geometry().center().x());
windowGeometry.moveCenter(QPoint(centerX, windowGeometry.center().y()));
}
if (y1 < 0) {
const int centerY = qMin(qAbs(y1) + windowGeometry.center().y(),
geometry().center().y());
windowGeometry.moveCenter(QPoint(windowGeometry.center().x(), centerY));
}
if (x2 > geometry().width()) {
const int centerX = qMax(windowGeometry.center().x() - (x2 - geometry().width()),
geometry().center().x());
windowGeometry.moveCenter(QPoint(centerX, windowGeometry.center().y()));
}
if (y2 > geometry().height()) {
const int centerY = qMax(windowGeometry.center().y() - (y2 - geometry().height()),
geometry().center().y());
windowGeometry.moveCenter(QPoint(windowGeometry.center().x(), centerY));
}
}
// at this point, if the window is still clipped,
// it means that it's too big to fit on the screen,
// so we need to proportionally shrink it
if (!geometry().contains(windowGeometry)) {
QSize newSize = windowGeometry.size();
newSize.scale(geometry().size(), Qt::KeepAspectRatio);
windowGeometry.setSize(newSize);
if (windowGeometry.x() < 0)
windowGeometry.moveCenter(QPoint(geometry().center().x(), windowGeometry.center().y()));
if (windowGeometry.y() < 0)
windowGeometry.moveCenter(QPoint(windowGeometry.center().x(), geometry().center().y()));
}
w->setGeometry(windowGeometry);
}
/*!
Adjust windows to the new screen geometry.
*/
void QQnxScreen::resizeWindows(const QRect &previousScreenGeometry)
{
resizeMaximizedWindows();
Q_FOREACH (QQnxWindow *w, m_childWindows) {
if (w->window()->windowState() & Qt::WindowFullScreen || w->window()->windowState() & Qt::WindowMaximized)
continue;
if (w->parent()) {
// This is a native (non-alien) widget window
resizeNativeWidgetWindow(w, previousScreenGeometry);
} else {
// This is a toplevel window
resizeTopLevelWindow(w, previousScreenGeometry);
}
}
}
QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) const
{
Q_FOREACH (QQnxWindow *window, m_childWindows) {
QQnxWindow * const result = window->findWindow(windowHandle);
if (result)
return result;
}
return 0;
}
void QQnxScreen::addWindow(QQnxWindow *window)
{
qScreenDebug() << "window =" << window;
if (m_childWindows.contains(window))
return;
if (window->window()->type() != Qt::CoverWindow) {
// Ensure that the desktop window is at the bottom of the zorder.
// If we do not do this then we may end up activating the desktop
// when the navigator service gets an event that our window group
// has been activated (see QQnxScreen::activateWindowGroup()).
// Such a situation would strangely break focus handling due to the
// invisible desktop widget window being layered on top of normal
// windows
if (window->window()->type() == Qt::Desktop)
m_childWindows.push_front(window);
else
m_childWindows.push_back(window);
updateHierarchy();
}
}
void QQnxScreen::removeWindow(QQnxWindow *window)
{
qScreenDebug() << "window =" << window;
if (window != m_coverWindow) {
const int numWindowsRemoved = m_childWindows.removeAll(window);
if (window == m_rootWindow) //We just removed the root window
m_rootWindow = 0; //TODO we need a new root window ;)
if (numWindowsRemoved > 0)
updateHierarchy();
} else {
m_coverWindow = 0;
}
}
void QQnxScreen::raiseWindow(QQnxWindow *window)
{
qScreenDebug() << "window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
m_childWindows.push_back(window);
}
}
void QQnxScreen::lowerWindow(QQnxWindow *window)
{
qScreenDebug() << "window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
m_childWindows.push_front(window);
}
}
void QQnxScreen::updateHierarchy()
{
qScreenDebug();
QList<QQnxWindow*>::const_iterator it;
int result;
int topZorder = 0;
errno = 0;
if (rootWindow()) {
result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder);
if (result != 0) { //This can happen if we use winId in QWidgets
topZorder = 10;
qWarning("QQnxScreen: failed to query root window z-order, errno=%d", errno);
}
} else {
topZorder = 0; //We do not need z ordering on the secondary screen, because only one window
//is supported there
}
topZorder++; // root window has the lowest z-order in the windowgroup
int underlayZorder = -1;
// Underlays sit immediately above the root window in the z-ordering
Q_FOREACH (screen_window_t underlay, m_underlays) {
// Do nothing when this fails. This can happen if we have stale windows in m_underlays,
// which in turn can happen because a window was removed but we didn't get a notification
// yet.
screen_set_window_property_iv(underlay, SCREEN_PROPERTY_ZORDER, &underlayZorder);
underlayZorder--;
}
// Normal Qt windows come next above the root window z-ordering
for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it)
(*it)->updateZorder(topZorder);
// Finally overlays sit above all else in the z-ordering
Q_FOREACH (screen_window_t overlay, m_overlays) {
// No error handling, see underlay logic above
screen_set_window_property_iv(overlay, SCREEN_PROPERTY_ZORDER, &topZorder);
topZorder++;
}
// After a hierarchy update, we need to force a flush on all screens.
// Right now, all screens share a context.
screen_flush_context(m_screenContext, 0);
}
void QQnxScreen::adjustOrientation()
{
if (!m_primaryScreen)
return;
bool ok = false;
const int rotation = qEnvironmentVariableIntValue("ORIENTATION", &ok);
if (ok)
setRotation(rotation);
}
QPlatformCursor * QQnxScreen::cursor() const
{
return m_cursor;
}
void QQnxScreen::keyboardHeightChanged(int height)
{
if (height == m_keyboardHeight)
return;
m_keyboardHeight = height;
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
}
void QQnxScreen::addOverlayWindow(screen_window_t window)
{
m_overlays.append(window);
updateHierarchy();
}
void QQnxScreen::addUnderlayWindow(screen_window_t window)
{
m_underlays.append(window);
updateHierarchy();
}
void QQnxScreen::addMultimediaWindow(const QByteArray &id, screen_window_t window)
{
// find the QnxWindow this mmrenderer window is related to
QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, id);
if (!mmWindow)
return;
mmWindow->setMMRendererWindow(window);
updateHierarchy();
}
void QQnxScreen::removeOverlayOrUnderlayWindow(screen_window_t window)
{
const int numRemoved = m_overlays.removeAll(window) + m_underlays.removeAll(window);
if (numRemoved > 0) {
updateHierarchy();
Q_EMIT foreignWindowClosed(window);
}
}
void QQnxScreen::newWindowCreated(void *window)
{
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
screen_display_t display = 0;
if (screen_get_window_property_pv(windowHandle, SCREEN_PROPERTY_DISPLAY, (void**)&display) != 0) {
qWarning("QQnx: Failed to get screen for window, errno=%d", errno);
return;
}
int zorder;
if (screen_get_window_property_iv(windowHandle, SCREEN_PROPERTY_ZORDER, &zorder) != 0) {
qWarning("QQnx: Failed to get z-order for window, errno=%d", errno);
zorder = 0;
}
char windowNameBuffer[256] = { 0 };
QByteArray windowName;
if (screen_get_window_property_cv(windowHandle, SCREEN_PROPERTY_ID_STRING,
sizeof(windowNameBuffer) - 1, windowNameBuffer) != 0) {
qWarning("QQnx: Failed to get id for window, errno=%d", errno);
}
windowName = QByteArray(windowNameBuffer);
if (display == nativeDisplay()) {
// A window was created on this screen. If we don't know about this window yet, it means
// it was not created by Qt, but by some foreign library like the multimedia renderer, which
// creates an overlay window when playing a video.
//
// Treat all foreign windows as overlays, underlays or as windows
// created by the BlackBerry QtMultimedia plugin.
//
// In the case of the BlackBerry QtMultimedia plugin, we need to
// "attach" the foreign created mmrenderer window to the correct
// platform window (usually the one belonging to QVideoWidget) to
// ensure proper z-ordering.
//
// Otherwise, assume that if a foreign window already has a Z-Order both negative and
// less than the default Z-Order installed by mmrender on windows it creates,
// the windows should be treated as an underlay. Otherwise, we treat it as an overlay.
if (!windowName.isEmpty() && windowName.startsWith("MmRendererVideoWindowControl")) {
addMultimediaWindow(windowName, windowHandle);
} else if (!findWindow(windowHandle)) {
if (zorder <= MAX_UNDERLAY_ZORDER)
addUnderlayWindow(windowHandle);
else
addOverlayWindow(windowHandle);
Q_EMIT foreignWindowCreated(windowHandle);
}
}
}
void QQnxScreen::windowClosed(void *window)
{
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, windowHandle);
if (mmWindow)
mmWindow->clearMMRendererWindow();
else
removeOverlayOrUnderlayWindow(windowHandle);
}
void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
{
qScreenDebug();
if (!rootWindow() || id != rootWindow()->groupName())
return;
QWindow * const window = rootWindow()->window();
if (!window)
return;
QWindowSystemInterface::handleWindowStateChanged(window, state);
}
void QQnxScreen::activateWindowGroup(const QByteArray &id)
{
qScreenDebug();
if (!rootWindow() || id != rootWindow()->groupName())
return;
QWindow * const window = rootWindow()->window();
if (!window)
return;
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setExposed(true);
if (m_coverWindow)
m_coverWindow->setExposed(false);
}
void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
{
qScreenDebug();
if (!rootWindow() || id != rootWindow()->groupName())
return;
if (m_coverWindow)
m_coverWindow->setExposed(true);
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setExposed(false);
}
QQnxWindow *QQnxScreen::rootWindow() const
{
return m_rootWindow;
}
void QQnxScreen::setRootWindow(QQnxWindow *window)
{
// Optionally disable the screen power save
bool ok = false;
const int disablePowerSave = qEnvironmentVariableIntValue("QQNX_DISABLE_POWER_SAVE", &ok);
if (ok && disablePowerSave) {
const int mode = SCREEN_IDLE_MODE_KEEP_AWAKE;
int result = screen_set_window_property_iv(window->nativeHandle(), SCREEN_PROPERTY_IDLE_MODE, &mode);
if (result != 0)
qWarning("QQnxRootWindow: failed to disable power saving mode");
}
m_rootWindow = window;
}
QT_END_NAMESPACE