Revert "Move QWindowSystemInterface out of qpa."
[profile/ivi/qtbase.git] / src / plugins / platforms / qnx / qqnxscreen.cpp
1 /***************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqnxscreen.h"
43 #include "qqnxwindow.h"
44
45 #include <QtCore/QThread>
46 #include <QtCore/QDebug>
47 #include <qpa/qwindowsysteminterface.h>
48
49 #include <errno.h>
50
51 #ifdef QQNXSCREEN_DEBUG
52 #define qScreenDebug qDebug
53 #else
54 #define qScreenDebug QT_NO_QDEBUG_MACRO
55 #endif
56
57 QT_BEGIN_NAMESPACE
58
59 QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
60     : m_screenContext(screenContext),
61       m_display(display),
62       m_rootWindow(),
63       m_primaryScreen(primaryScreen),
64       m_posted(false),
65       m_keyboardHeight(0),
66       m_nativeOrientation(Qt::PrimaryOrientation),
67       m_platformContext(0)
68 {
69     qScreenDebug() << Q_FUNC_INFO;
70     // Cache initial orientation of this display
71     errno = 0;
72     int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation);
73     if (result != 0) {
74         qFatal("QQnxScreen: failed to query display rotation, errno=%d", errno);
75     }
76     m_currentRotation = m_initialRotation;
77
78     // Cache size of this display in pixels
79     errno = 0;
80     int val[2];
81     result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val);
82     if (result != 0) {
83         qFatal("QQnxScreen: failed to query display size, errno=%d", errno);
84     }
85
86     m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
87
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.
92     errno = 0;
93     result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val);
94     if (result != 0) {
95         qFatal("QQnxScreen: failed to query display physical size, errno=%d", errno);
96     }
97
98     m_nativeOrientation = val[0] >= val[1] ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
99
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]);
103     else
104         m_currentPhysicalSize = m_initialPhysicalSize = QSize(val[1], val[0]);
105
106     // We only create the root window if we are the primary display.
107     if (primaryScreen)
108         m_rootWindow = QSharedPointer<QQnxRootWindow>(new QQnxRootWindow(this));
109 }
110
111 QQnxScreen::~QQnxScreen()
112 {
113     qScreenDebug() << Q_FUNC_INFO;
114 }
115
116 static int defaultDepth()
117 {
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) {
125             defaultDepth = 32;
126         }
127     }
128     return defaultDepth;
129 }
130
131 QRect QQnxScreen::availableGeometry() const
132 {
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);
137 }
138
139 int QQnxScreen::depth() const
140 {
141     return defaultDepth();
142 }
143
144 qreal QQnxScreen::refreshRate() const
145 {
146     screen_display_mode_t displayMode;
147     int result = screen_get_display_property_pv(m_display, SCREEN_PROPERTY_MODE, reinterpret_cast<void **>(&displayMode));
148     if (result != 0) {
149         qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
150         return 60.0;
151     }
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);
158 }
159
160 Qt::ScreenOrientation QQnxScreen::nativeOrientation() const
161 {
162     return m_nativeOrientation;
163 }
164
165 Qt::ScreenOrientation QQnxScreen::orientation() const
166 {
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;
176         else
177             orient = Qt::InvertedPortraitOrientation;
178     } else {
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;
187         else
188             orient = Qt::InvertedLandscapeOrientation;
189     }
190     qScreenDebug() << Q_FUNC_INFO << "orientation =" << orient;
191     return orient;
192 }
193
194 /*!
195     Check if the supplied angles are perpendicular to each other.
196 */
197 static bool isOrthogonal(int angle1, int angle2)
198 {
199     return ((angle1 - angle2) % 180) != 0;
200 }
201
202 void QQnxScreen::setRotation(int rotation)
203 {
204     qScreenDebug() << Q_FUNC_INFO << "orientation =" << rotation;
205     // Check if rotation changed
206     if (m_currentRotation != rotation) {
207         // Update rotation of root window
208         if (m_rootWindow)
209             m_rootWindow->setRotation(rotation);
210
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());
215         } else {
216             m_currentGeometry = QRect(0, 0, m_initialGeometry.width(), m_initialGeometry.height());
217             m_currentPhysicalSize = m_initialPhysicalSize;
218         }
219
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();
223             if (m_rootWindow)
224                 m_rootWindow->resize(m_currentGeometry.size());
225         } else {
226             // TODO: Find one global place to flush display updates
227             // Force immediate display update if no geometry changes required
228             if (m_rootWindow)
229                 m_rootWindow->flush();
230         }
231
232         // Save new rotation
233         m_currentRotation = rotation;
234
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();
242         }
243
244         // Flush everything, so that the windows rotations are applied properly.
245         // Needed for non-maximized windows
246         screen_flush_context( m_screenContext, 0 );
247     }
248 }
249
250 QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle)
251 {
252     Q_FOREACH (QQnxWindow *window, m_childWindows) {
253         QQnxWindow * const result = window->findWindow(windowHandle);
254         if (result)
255             return result;
256     }
257
258     return 0;
259 }
260
261 void QQnxScreen::addWindow(QQnxWindow *window)
262 {
263     qScreenDebug() << Q_FUNC_INFO << "window =" << window;
264
265     if (m_childWindows.contains(window))
266         return;
267
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
274     // windows
275     if (window->window()->windowType() == Qt::Desktop)
276         m_childWindows.push_front(window);
277     else
278         m_childWindows.push_back(window);
279     updateHierarchy();
280 }
281
282 void QQnxScreen::removeWindow(QQnxWindow *window)
283 {
284     qScreenDebug() << Q_FUNC_INFO << "window =" << window;
285
286     const int numWindowsRemoved = m_childWindows.removeAll(window);
287     if (numWindowsRemoved > 0)
288         updateHierarchy();
289 }
290
291 void QQnxScreen::raiseWindow(QQnxWindow *window)
292 {
293     qScreenDebug() << Q_FUNC_INFO << "window =" << window;
294
295     removeWindow(window);
296     m_childWindows.push_back(window);
297     updateHierarchy();
298 }
299
300 void QQnxScreen::lowerWindow(QQnxWindow *window)
301 {
302     qScreenDebug() << Q_FUNC_INFO << "window =" << window;
303
304     removeWindow(window);
305     m_childWindows.push_front(window);
306     updateHierarchy();
307 }
308
309 void QQnxScreen::updateHierarchy()
310 {
311     qScreenDebug() << Q_FUNC_INFO;
312
313     QList<QQnxWindow*>::const_iterator it;
314     int topZorder = 1; // root window is z-order 0, all "top" level windows are "above" it
315
316     for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it)
317         (*it)->updateZorder(topZorder);
318
319     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
323         // yet.
324         screen_set_window_property_iv(overlay, SCREEN_PROPERTY_ZORDER, &topZorder);
325         topZorder++;
326     }
327
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 );
331 }
332
333 void QQnxScreen::onWindowPost(QQnxWindow *window)
334 {
335     qScreenDebug() << Q_FUNC_INFO;
336     Q_UNUSED(window)
337
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
340     // never changes
341     if (!m_posted && m_rootWindow) {
342         m_rootWindow->post();
343         m_posted = true;
344     }
345 }
346
347 void QQnxScreen::keyboardHeightChanged(int height)
348 {
349     if (height == m_keyboardHeight)
350         return;
351
352     m_keyboardHeight = height;
353
354     QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry());
355 }
356
357 void QQnxScreen::addOverlayWindow(screen_window_t window)
358 {
359     m_overlays.append(window);
360     updateHierarchy();
361 }
362
363 void QQnxScreen::removeOverlayWindow(screen_window_t window)
364 {
365     const int numOverlaysRemoved = m_overlays.removeAll(window);
366     if (numOverlaysRemoved > 0)
367         updateHierarchy();
368 }
369
370 void QQnxScreen::newWindowCreated(void *window)
371 {
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);
377         return;
378     }
379
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);
387     }
388 }
389
390 void QQnxScreen::windowClosed(void *window)
391 {
392     Q_ASSERT(thread() == QThread::currentThread());
393     const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
394     removeOverlayWindow(windowHandle);
395 }
396
397 void QQnxScreen::activateWindowGroup(const QByteArray &id)
398 {
399     qScreenDebug() << Q_FUNC_INFO;
400
401     if (!rootWindow() || id != rootWindow()->groupName())
402         return;
403
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);
410     }
411 }
412
413 void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
414 {
415     qScreenDebug() << Q_FUNC_INFO;
416
417     if (!rootWindow() || id != rootWindow()->groupName())
418         return;
419
420     QWindowSystemInterface::handleWindowActivated(0);
421 }
422
423 QT_END_NAMESPACE