549e3437bc28ee6cfba9d65dbc5973093060f841
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandwindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the config.tests of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylandwindow.h"
43
44 #include "qwaylandbuffer.h"
45 #include "qwaylanddisplay.h"
46 #include "qwaylandinputdevice.h"
47 #include "qwaylandscreen.h"
48 #include "qwaylandshell.h"
49 #include "qwaylandshellsurface.h"
50 #include "qwaylandextendedsurface.h"
51 #include "qwaylandsubsurface.h"
52 #include "qwaylanddecoration.h"
53
54 #include <QtGui/QWindow>
55
56 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
57 #include "windowmanager_integration/qwaylandwindowmanagerintegration.h"
58 #endif
59
60 #include <QCoreApplication>
61 #include <qpa/qwindowsysteminterface.h>
62
63 #include <QtCore/QDebug>
64
65 QWaylandWindow::QWaylandWindow(QWindow *window)
66     : QPlatformWindow(window)
67     , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display())
68     , mSurface(mDisplay->createSurface(this))
69     , mShellSurface(0)
70     , mExtendedWindow(0)
71     , mSubSurfaceWindow(0)
72     , mWindowDecoration(0)
73     , mMouseEventsInContentArea(false)
74     , mMousePressedInContentArea(Qt::NoButton)
75     , mBuffer(0)
76     , mWaitingForFrameSync(false)
77     , mFrameCallback(0)
78     , mSentInitialResize(false)
79 {
80     static WId id = 1;
81     mWindowId = id++;
82
83     if (mDisplay->shell())
84         mShellSurface = mDisplay->shell()->getShellSurface(this);
85     if (mDisplay->windowExtension())
86         mExtendedWindow = mDisplay->windowExtension()->getExtendedWindow(this);
87     if (mDisplay->subSurfaceExtension())
88         mSubSurfaceWindow = mDisplay->subSurfaceExtension()->getSubSurfaceAwareWindow(this);
89
90 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
91     mDisplay->windowManagerIntegration()->mapClientToProcess(qApp->applicationPid());
92     mDisplay->windowManagerIntegration()->authenticateWithToken();
93 #endif
94
95     if (parent() && mSubSurfaceWindow) {
96         mSubSurfaceWindow->setParent(static_cast<const QWaylandWindow *>(parent()));
97     } else if (window->transientParent()) {
98         if (window->transientParent()) {
99             mShellSurface->updateTransientParent(window->transientParent());
100         }
101     } else {
102         mShellSurface->setTopLevel();
103     }
104
105     setWindowFlags(window->windowFlags());
106 }
107
108 QWaylandWindow::~QWaylandWindow()
109 {
110     if (mSurface) {
111         delete mShellSurface;
112         delete mExtendedWindow;
113         wl_surface_destroy(mSurface);
114     }
115
116     QList<QWaylandInputDevice *> inputDevices = mDisplay->inputDevices();
117     for (int i = 0; i < inputDevices.size(); ++i)
118         inputDevices.at(i)->handleWindowDestroyed(this);
119 }
120
121 WId QWaylandWindow::winId() const
122 {
123     return mWindowId;
124 }
125
126 void QWaylandWindow::setParent(const QPlatformWindow *parent)
127 {
128     const QWaylandWindow *parentWaylandWindow = static_cast<const QWaylandWindow *>(parent);
129     if (subSurfaceWindow()) {
130         subSurfaceWindow()->setParent(parentWaylandWindow);
131     }
132 }
133
134 void QWaylandWindow::setWindowTitle(const QString &title)
135 {
136     if (mShellSurface) {
137         QByteArray titleUtf8 = title.toUtf8();
138         mShellSurface->setTitle(titleUtf8.constData());
139     }
140     if (mWindowDecoration && window()->isVisible()) {
141         mWindowDecoration->paintDecoration();
142     }
143 }
144
145 void QWaylandWindow::setGeometry(const QRect &rect)
146 {
147     QPlatformWindow::setGeometry(rect);
148
149     if (shellSurface() && window()->transientParent())
150         shellSurface()->updateTransientParent(window()->transientParent());
151 }
152
153 void QWaylandWindow::setVisible(bool visible)
154 {
155
156     if (visible) {
157         if (mBuffer)
158             wl_surface_attach(mSurface, mBuffer->buffer(), 0, 0);
159
160         if (!mSentInitialResize) {
161             QWindowSystemInterface::handleGeometryChange(window(), geometry());
162             QWindowSystemInterface::flushWindowSystemEvents();
163             mSentInitialResize = true;
164         }
165
166         QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
167         QWindowSystemInterface::flushWindowSystemEvents();
168     } else {
169         QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
170         QWindowSystemInterface::flushWindowSystemEvents();
171         wl_surface_attach(mSurface, 0,0,0);
172         damage(QRect(QPoint(0,0),geometry().size()));
173     }
174 }
175
176
177 bool QWaylandWindow::isExposed() const
178 {
179     if (!window()->isVisible())
180         return false;
181     if (mExtendedWindow)
182         return mExtendedWindow->isExposed();
183     return true;
184 }
185
186
187 void QWaylandWindow::configure(uint32_t edges, int32_t width, int32_t height)
188 {
189     Q_UNUSED(edges);
190
191     int widthWithoutMargins = qMax(width-(frameMargins().left() +frameMargins().right()),1);
192     int heightWithoutMargins = qMax(height-(frameMargins().top()+frameMargins().bottom()),1);
193
194     widthWithoutMargins = qMax(widthWithoutMargins, window()->minimumSize().width());
195     heightWithoutMargins = qMax(heightWithoutMargins, window()->minimumSize().height());
196     QRect geometry = QRect(0,0,
197                            widthWithoutMargins, heightWithoutMargins);
198     setGeometry(geometry);
199     QWindowSystemInterface::handleGeometryChange(window(), geometry);
200 }
201
202 void QWaylandWindow::attach(QWaylandBuffer *buffer)
203 {
204     mBuffer = buffer;
205
206     if (window()->isVisible()) {
207         wl_surface_attach(mSurface, mBuffer->buffer(),0,0);
208     }
209 }
210
211 QWaylandBuffer *QWaylandWindow::attached() const
212 {
213     return mBuffer;
214 }
215
216 void QWaylandWindow::damage(const QRect &rect)
217 {
218     //We have to do sync stuff before calling damage, or we might
219     //get a frame callback before we get the timestamp
220     if (!mWaitingForFrameSync) {
221         mFrameCallback = wl_surface_frame(mSurface);
222         wl_callback_add_listener(mFrameCallback,&QWaylandWindow::callbackListener,this);
223         mWaitingForFrameSync = true;
224     }
225
226     wl_surface_damage(mSurface,
227                       rect.x(), rect.y(), rect.width(), rect.height());
228 }
229
230 const wl_callback_listener QWaylandWindow::callbackListener = {
231     QWaylandWindow::frameCallback
232 };
233
234 void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uint32_t time)
235 {
236     Q_UNUSED(time);
237     QWaylandWindow *self = static_cast<QWaylandWindow*>(data);
238     if (callback != self->mFrameCallback) // might be a callback caused by the shm backingstore
239         return;
240     self->mWaitingForFrameSync = false;
241     if (self->mFrameCallback) {
242         wl_callback_destroy(self->mFrameCallback);
243         self->mFrameCallback = 0;
244     }
245 }
246
247 void QWaylandWindow::waitForFrameSync()
248 {
249     if (!mWaitingForFrameSync)
250         return;
251     mDisplay->flushRequests();
252     while (mWaitingForFrameSync)
253         mDisplay->blockingReadEvents();
254 }
255
256 QMargins QWaylandWindow::frameMargins() const
257 {
258     if (mWindowDecoration)
259         return mWindowDecoration->margins();
260     return QPlatformWindow::frameMargins();
261 }
262
263 QWaylandShellSurface *QWaylandWindow::shellSurface() const
264 {
265     return mShellSurface;
266 }
267
268 QWaylandExtendedSurface *QWaylandWindow::extendedWindow() const
269 {
270     return mExtendedWindow;
271 }
272
273 QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const
274 {
275     return mSubSurfaceWindow;
276 }
277
278 void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
279 {
280     if (mExtendedWindow)
281         mExtendedWindow->setContentOrientation(orientation);
282 }
283
284 Qt::ScreenOrientation QWaylandWindow::requestWindowOrientation(Qt::ScreenOrientation orientation)
285 {
286     if (mExtendedWindow) {
287         mExtendedWindow->setWindowOrientation(orientation);
288         return orientation;
289     }
290
291     return Qt::PrimaryOrientation;
292 }
293
294 Qt::WindowState QWaylandWindow::setWindowState(Qt::WindowState state)
295 {
296     if (state == Qt::WindowFullScreen || state == Qt::WindowMaximized) {
297         QScreen *screen = window()->screen();
298
299         QRect geometry = screen->mapBetween(window()->windowOrientation(), screen->primaryOrientation(), screen->geometry());
300         setGeometry(geometry);
301
302         QWindowSystemInterface::handleGeometryChange(window(), geometry);
303
304         return state;
305     }
306
307     return Qt::WindowNoState;
308 }
309
310 void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags)
311 {
312     if (mExtendedWindow)
313         mExtendedWindow->setWindowFlags(flags);
314 }
315
316 QWaylandDecoration *QWaylandWindow::decoration() const
317 {
318     return mWindowDecoration;
319 }
320
321 void QWaylandWindow::setDecoration(QWaylandDecoration *decoration)
322 {
323     mWindowDecoration = decoration;
324     if (subSurfaceWindow()) {
325         subSurfaceWindow()->adjustPositionOfChildren();
326     }
327 }
328
329 void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
330 {
331     if (mWindowDecoration) {
332         handleMouseEventWithDecoration(inputDevice, timestamp,local,global,b,mods);
333         return;
334     }
335
336     QWindowSystemInterface::handleMouseEvent(window(),timestamp,local,global,b,mods);
337 }
338
339 void QWaylandWindow::handleMouseEnter()
340 {
341     if (!mWindowDecoration) {
342         QWindowSystemInterface::handleEnterEvent(window());
343     }
344 }
345
346 void QWaylandWindow::handleMouseLeave()
347 {
348     if (mWindowDecoration) {
349         if (mMouseEventsInContentArea) {
350             QWindowSystemInterface::handleLeaveEvent(window());
351         }
352         mWindowDecoration->restoreMouseCursor();
353     } else {
354         QWindowSystemInterface::handleLeaveEvent(window());
355     }
356 }
357
358 void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
359 {
360     if (mWindowDecoration->inMouseButtonPressedState()) {
361         mWindowDecoration->handleMouse(inputDevice,local,global,b,mods);
362         return;
363     }
364
365     QMargins marg = frameMargins();
366     QRect windowRect(0 + marg.left(),
367                      0 + marg.top(),
368                      geometry().size().width() - marg.right(),
369                      geometry().size().height() - marg.bottom());
370     if (windowRect.contains(local.toPoint()) || mMousePressedInContentArea != Qt::NoButton) {
371         QPointF localTranslated = local;
372         QPointF globalTranslated = global;
373         localTranslated.setX(localTranslated.x() - marg.left());
374         localTranslated.setY(localTranslated.y() - marg.top());
375         globalTranslated.setX(globalTranslated.x() - marg.left());
376         globalTranslated.setY(globalTranslated.y() - marg.top());
377         if (!mMouseEventsInContentArea) {
378             mWindowDecoration->restoreMouseCursor();
379             QWindowSystemInterface::handleEnterEvent(window());
380         }
381         QWindowSystemInterface::handleMouseEvent(window(), timestamp, localTranslated, globalTranslated, b, mods);
382         mMouseEventsInContentArea = true;
383         mMousePressedInContentArea = b;
384     } else {
385         if (mMouseEventsInContentArea) {
386             QWindowSystemInterface::handleLeaveEvent(window());
387             mMouseEventsInContentArea = false;
388         }
389         mWindowDecoration->handleMouse(inputDevice,local,global,b,mods);
390     }
391 }