1 /***************************************************************************
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqnxscreen.h"
43 #include "qqnxwindow.h"
45 #include <QtCore/QThread>
46 #include <QtCore/QDebug>
47 #include <qpa/qwindowsysteminterface.h>
51 #ifdef QQNXSCREEN_DEBUG
52 #define qScreenDebug qDebug
54 #define qScreenDebug QT_NO_QDEBUG_MACRO
59 QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
60 : m_screenContext(screenContext),
63 m_primaryScreen(primaryScreen),
66 m_nativeOrientation(Qt::PrimaryOrientation),
69 qScreenDebug() << Q_FUNC_INFO;
70 // Cache initial orientation of this display
72 int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation);
74 qFatal("QQnxScreen: failed to query display rotation, errno=%d", errno);
76 m_currentRotation = m_initialRotation;
78 // Cache size of this display in pixels
81 result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val);
83 qFatal("QQnxScreen: failed to query display size, errno=%d", errno);
86 m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
88 // Cache size of this display in millimeters. We have to take care of the orientation.
89 // libscreen always reports the physical size dimensions as width and height in the
90 // native orientation. Contrary to this, QPlatformScreen::physicalSize() expects the
91 // returned dimensions to follow the current orientation.
93 result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val);
95 qFatal("QQnxScreen: failed to query display physical size, errno=%d", errno);
98 m_nativeOrientation = val[0] >= val[1] ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
100 const int angle = screen()->angleBetween(m_nativeOrientation, orientation());
101 if (angle == 0 || angle == 180)
102 m_currentPhysicalSize = m_initialPhysicalSize = QSize(val[0], val[1]);
104 m_currentPhysicalSize = m_initialPhysicalSize = QSize(val[1], val[0]);
106 // We only create the root window if we are the primary display.
108 m_rootWindow = QSharedPointer<QQnxRootWindow>(new QQnxRootWindow(this));
111 QQnxScreen::~QQnxScreen()
113 qScreenDebug() << Q_FUNC_INFO;
116 static int defaultDepth()
118 qScreenDebug() << Q_FUNC_INFO;
119 static int defaultDepth = 0;
120 if (defaultDepth == 0) {
121 // check if display depth was specified in environment variable;
122 // use default value if no valid value found
123 defaultDepth = qgetenv("QQNX_DISPLAY_DEPTH").toInt();
124 if (defaultDepth != 16 && defaultDepth != 32) {
131 QRect QQnxScreen::availableGeometry() const
133 qScreenDebug() << Q_FUNC_INFO;
134 // available geometry = total geometry - keyboard
135 return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
136 m_currentGeometry.width(), m_currentGeometry.height() - m_keyboardHeight);
139 int QQnxScreen::depth() const
141 return defaultDepth();
144 qreal QQnxScreen::refreshRate() const
146 screen_display_mode_t displayMode;
147 int result = screen_get_display_property_pv(m_display, SCREEN_PROPERTY_MODE, reinterpret_cast<void **>(&displayMode));
149 qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
152 qScreenDebug() << Q_FUNC_INFO << "screen mode:" << endl
153 << " width =" << displayMode.width << endl
154 << " height =" << displayMode.height << endl
155 << " refresh =" << displayMode.refresh << endl
156 << " interlaced =" << displayMode.interlaced;
157 return static_cast<qreal>(displayMode.refresh);
160 Qt::ScreenOrientation QQnxScreen::nativeOrientation() const
162 return m_nativeOrientation;
165 Qt::ScreenOrientation QQnxScreen::orientation() const
167 Qt::ScreenOrientation orient;
168 if (m_nativeOrientation == Qt::LandscapeOrientation) {
169 // Landscape devices e.g. PlayBook
170 if (m_currentRotation == 0)
171 orient = Qt::LandscapeOrientation;
172 else if (m_currentRotation == 90)
173 orient = Qt::PortraitOrientation;
174 else if (m_currentRotation == 180)
175 orient = Qt::InvertedLandscapeOrientation;
177 orient = Qt::InvertedPortraitOrientation;
179 // Portrait devices e.g. Phones
180 // ###TODO Check these on an actual phone device
181 if (m_currentRotation == 0)
182 orient = Qt::PortraitOrientation;
183 else if (m_currentRotation == 90)
184 orient = Qt::LandscapeOrientation;
185 else if (m_currentRotation == 180)
186 orient = Qt::InvertedPortraitOrientation;
188 orient = Qt::InvertedLandscapeOrientation;
190 qScreenDebug() << Q_FUNC_INFO << "orientation =" << orient;
195 Check if the supplied angles are perpendicular to each other.
197 static bool isOrthogonal(int angle1, int angle2)
199 return ((angle1 - angle2) % 180) != 0;
202 void QQnxScreen::setRotation(int rotation)
204 qScreenDebug() << Q_FUNC_INFO << "orientation =" << rotation;
205 // Check if rotation changed
206 if (m_currentRotation != rotation) {
207 // Update rotation of root window
209 m_rootWindow->setRotation(rotation);
211 // Swap dimensions if we've rotated 90 or 270 from initial orientation
212 if (isOrthogonal(m_initialRotation, rotation)) {
213 m_currentGeometry = QRect(0, 0, m_initialGeometry.height(), m_initialGeometry.width());
214 m_currentPhysicalSize = QSize(m_initialPhysicalSize.height(), m_initialPhysicalSize.width());
216 m_currentGeometry = QRect(0, 0, m_initialGeometry.width(), m_initialGeometry.height());
217 m_currentPhysicalSize = m_initialPhysicalSize;
220 // Resize root window if we've rotated 90 or 270 from previous orientation
221 if (isOrthogonal(m_currentRotation, rotation)) {
222 qScreenDebug() << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
224 m_rootWindow->resize(m_currentGeometry.size());
226 // TODO: Find one global place to flush display updates
227 // Force immediate display update if no geometry changes required
229 m_rootWindow->flush();
233 m_currentRotation = rotation;
235 // TODO: check if other screens are supposed to rotate as well and/or whether this depends
236 // on if clone mode is being used.
237 // Rotating only the primary screen is what we had in the navigator event handler before refactoring
238 if (m_primaryScreen) {
239 QWindowSystemInterface::handleScreenOrientationChange(screen(), orientation());
240 QWindowSystemInterface::handleScreenGeometryChange(screen(), m_currentGeometry);
241 resizeMaximizedWindows();
244 // Flush everything, so that the windows rotations are applied properly.
245 // Needed for non-maximized windows
246 screen_flush_context( m_screenContext, 0 );
250 QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle)
252 Q_FOREACH (QQnxWindow *window, m_childWindows) {
253 QQnxWindow * const result = window->findWindow(windowHandle);
261 void QQnxScreen::addWindow(QQnxWindow *window)
263 qScreenDebug() << Q_FUNC_INFO << "window =" << window;
265 if (m_childWindows.contains(window))
268 // Ensure that the desktop window is at the bottom of the zorder.
269 // If we do not do this then we may end up activating the desktop
270 // when the navigator service gets an event that our window group
271 // has been activated (see QQnxScreen::activateWindowGroup()).
272 // Such a situation would strangely break focus handling due to the
273 // invisible desktop widget window being layered on top of normal
275 if (window->window()->windowType() == Qt::Desktop)
276 m_childWindows.push_front(window);
278 m_childWindows.push_back(window);
282 void QQnxScreen::removeWindow(QQnxWindow *window)
284 qScreenDebug() << Q_FUNC_INFO << "window =" << window;
286 const int numWindowsRemoved = m_childWindows.removeAll(window);
287 if (numWindowsRemoved > 0)
291 void QQnxScreen::raiseWindow(QQnxWindow *window)
293 qScreenDebug() << Q_FUNC_INFO << "window =" << window;
295 removeWindow(window);
296 m_childWindows.push_back(window);
300 void QQnxScreen::lowerWindow(QQnxWindow *window)
302 qScreenDebug() << Q_FUNC_INFO << "window =" << window;
304 removeWindow(window);
305 m_childWindows.push_front(window);
309 void QQnxScreen::updateHierarchy()
311 qScreenDebug() << Q_FUNC_INFO;
313 QList<QQnxWindow*>::const_iterator it;
314 int topZorder = 1; // root window is z-order 0, all "top" level windows are "above" it
316 for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it)
317 (*it)->updateZorder(topZorder);
320 Q_FOREACH (screen_window_t overlay, m_overlays) {
321 // Do nothing when this fails. This can happen if we have stale windows in mOverlays,
322 // which in turn can happen because a window was removed but we didn't get a notification
324 screen_set_window_property_iv(overlay, SCREEN_PROPERTY_ZORDER, &topZorder);
328 // After a hierarchy update, we need to force a flush on all screens.
329 // Right now, all screens share a context.
330 screen_flush_context( m_screenContext, 0 );
333 void QQnxScreen::onWindowPost(QQnxWindow *window)
335 qScreenDebug() << Q_FUNC_INFO;
338 // post app window (so navigator will show it) after first child window
339 // has posted; this only needs to happen once as the app window's content
341 if (!m_posted && m_rootWindow) {
342 m_rootWindow->post();
347 void QQnxScreen::keyboardHeightChanged(int height)
349 if (height == m_keyboardHeight)
352 m_keyboardHeight = height;
354 QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry());
357 void QQnxScreen::addOverlayWindow(screen_window_t window)
359 m_overlays.append(window);
363 void QQnxScreen::removeOverlayWindow(screen_window_t window)
365 const int numOverlaysRemoved = m_overlays.removeAll(window);
366 if (numOverlaysRemoved > 0)
370 void QQnxScreen::newWindowCreated(void *window)
372 Q_ASSERT(thread() == QThread::currentThread());
373 const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
374 screen_display_t display = NULL;
375 if (screen_get_window_property_pv(windowHandle, SCREEN_PROPERTY_DISPLAY, (void**)&display) != 0) {
376 qWarning("QQnx: Failed to get screen for window, errno=%d", errno);
380 if (display == nativeDisplay()) {
381 // A window was created on this screen. If we don't know about this window yet, it means
382 // it was not created by Qt, but by some foreign library like the multimedia renderer, which
383 // creates an overlay window when playing a video.
384 // Treat all foreign windows as overlays here.
385 if (!findWindow(windowHandle))
386 addOverlayWindow(windowHandle);
390 void QQnxScreen::windowClosed(void *window)
392 Q_ASSERT(thread() == QThread::currentThread());
393 const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
394 removeOverlayWindow(windowHandle);
397 void QQnxScreen::activateWindowGroup(const QByteArray &id)
399 qScreenDebug() << Q_FUNC_INFO;
401 if (!rootWindow() || id != rootWindow()->groupName())
404 if (!m_childWindows.isEmpty()) {
405 // We're picking up the last window of the list here
406 // because this list is ordered by stacking order.
407 // Last window is effectively the one on top.
408 QWindow * const window = m_childWindows.last()->window();
409 QWindowSystemInterface::handleWindowActivated(window);
413 void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
415 qScreenDebug() << Q_FUNC_INFO;
417 if (!rootWindow() || id != rootWindow()->groupName())
420 QWindowSystemInterface::handleWindowActivated(0);