Updated to use the Thread affinity patch that we tried to upstream
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylanddisplay.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
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 "qwaylanddisplay.h"
43
44 #include "qwaylandwindow.h"
45 #include "qwaylandscreen.h"
46 #include "qwaylandcursor.h"
47 #include "qwaylandinputdevice.h"
48 #include "qwaylandclipboard.h"
49 #include "qwaylanddatadevicemanager.h"
50 #include "qwaylandshell.h"
51
52 #ifdef QT_WAYLAND_GL_SUPPORT
53 #include "gl_integration/qwaylandglintegration.h"
54 #endif
55
56 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
57 #include "windowmanager_integration/qwaylandwindowmanagerintegration.h"
58 #endif
59
60 #include "qwaylandextendedoutput.h"
61 #include "qwaylandextendedsurface.h"
62 #include "qwaylandsubsurface.h"
63 #include "qwaylandtouch.h"
64
65 #include <QtCore/QAbstractEventDispatcher>
66 #include <QtGui/private/qguiapplication_p.h>
67
68 #include <unistd.h>
69 #include <fcntl.h>
70 #include <stdio.h>
71 #include <errno.h>
72
73 #include <QtCore/QDebug>
74
75 struct wl_surface *QWaylandDisplay::createSurface(void *handle)
76 {
77     struct wl_surface * surface = wl_compositor_create_surface(mCompositor);
78     wl_surface_set_user_data(surface, handle);
79     return surface;
80 }
81
82 #ifdef QT_WAYLAND_GL_SUPPORT
83 QWaylandGLIntegration * QWaylandDisplay::eglIntegration()
84 {
85     return mEglIntegration;
86 }
87 #endif
88
89 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
90 QWaylandWindowManagerIntegration *QWaylandDisplay::windowManagerIntegration()
91 {
92     return mWindowManagerIntegration;
93 }
94 #endif
95
96 QWaylandInputDevice *QWaylandDisplay::lastKeyboardFocusInputDevice() const
97 {
98     return mLastKeyboardFocusInputDevice;
99 }
100
101 void QWaylandDisplay::setLastKeyboardFocusInputDevice(QWaylandInputDevice *device)
102 {
103     qDebug() << "setting last keyboard focus input device" << device;
104     mLastKeyboardFocusInputDevice = device;
105 }
106
107 static QWaylandDisplay *display = 0;
108
109 static int dummyUpdate(uint32_t, void *)
110 {
111     return 0;
112 }
113
114 QWaylandDisplay::QWaylandDisplay(void)
115     : mLastKeyboardFocusInputDevice(0)
116     , mDndSelectionHandler(0)
117     , mWindowExtension(0)
118     , mSubSurfaceExtension(0)
119     , mOutputExtension(0)
120     , mTouchExtension(0)
121 {
122     display = this;
123     qRegisterMetaType<uint32_t>("uint32_t");
124
125     mDisplay = wl_display_connect(NULL);
126     if (mDisplay == NULL) {
127         qErrnoWarning(errno, "Failed to create display");
128         qFatal("No wayland connection available.");
129     }
130
131     wl_display_add_global_listener(mDisplay, QWaylandDisplay::displayHandleGlobal, this);
132
133     mFd = wl_display_get_fd(mDisplay, dummyUpdate, 0);
134
135 #ifdef WAYLAND_CLIENT_THREAD_AFFINITY
136     mWritableNotificationFd = wl_display_get_write_notification_fd(mDisplay);
137     QSocketNotifier *wn = new QSocketNotifier(mWritableNotificationFd, QSocketNotifier::Read, this);
138     connect(wn, SIGNAL(activated(int)), this, SLOT(flushRequests()));
139 #else
140     QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
141     connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(flushRequests()));
142 #endif
143
144     mReadNotifier = new QSocketNotifier(mFd, QSocketNotifier::Read, this);
145     connect(mReadNotifier, SIGNAL(activated(int)), this, SLOT(readEvents()));
146
147 #ifdef QT_WAYLAND_GL_SUPPORT
148     mEglIntegration = QWaylandGLIntegration::createGLIntegration(this);
149 #endif
150
151 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
152     mWindowManagerIntegration = QWaylandWindowManagerIntegration::createIntegration(this);
153 #endif
154
155     blockingReadEvents();
156
157 #ifdef QT_WAYLAND_GL_SUPPORT
158     mEglIntegration->initialize();
159 #endif
160
161     waitForScreens();
162 }
163
164 QWaylandDisplay::~QWaylandDisplay(void)
165 {
166 #ifdef QT_WAYLAND_GL_SUPPORT
167     delete mEglIntegration;
168 #endif
169     wl_display_destroy(mDisplay);
170 }
171
172 void QWaylandDisplay::createNewScreen(struct wl_output *output, QRect geometry)
173 {
174     QWaylandScreen *waylandScreen = new QWaylandScreen(this,output,geometry);
175     mScreens.append(waylandScreen);
176 }
177
178 void QWaylandDisplay::flushRequests()
179 {
180     wl_display_flush(mDisplay);
181 }
182
183 void QWaylandDisplay::readEvents()
184 {
185     fd_set fds;
186     FD_ZERO(&fds);
187     FD_SET(mFd, &fds);
188
189     fd_set nds;
190     FD_ZERO(&nds);
191     fd_set rs = fds;
192     fd_set ws = nds;
193     fd_set es = nds;
194     timeval timeout;
195
196     timeout.tv_sec = 0;
197     timeout.tv_usec = 0;
198
199     int ret = ::select(mFd+1, &rs, &ws, &es, &timeout );
200
201     if (ret <= 0) {
202         return;
203     }
204
205     wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
206 }
207
208 void QWaylandDisplay::blockingReadEvents()
209 {
210     wl_display_iterate(mDisplay, WL_DISPLAY_READABLE);
211 }
212
213 QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
214 {
215     for (int i = 0; i < mScreens.size(); ++i) {
216         QWaylandScreen *screen = static_cast<QWaylandScreen *>(mScreens.at(i));
217         if (screen->output() == output)
218             return screen;
219     }
220     return 0;
221 }
222
223 void QWaylandDisplay::outputHandleGeometry(void *data,
224                                            wl_output *output,
225                                            int32_t x, int32_t y,
226                                            int32_t physicalWidth,
227                                            int32_t physicalHeight,
228                                            int subpixel,
229                                            const char *make, const char *model)
230 {
231     Q_UNUSED(subpixel);
232     Q_UNUSED(make);
233     Q_UNUSED(model);
234     QWaylandDisplay *waylandDisplay = static_cast<QWaylandDisplay *>(data);
235     QRect outputRect = QRect(x, y, physicalWidth, physicalHeight);
236     waylandDisplay->createNewScreen(output,outputRect);
237 }
238
239 void QWaylandDisplay::mode(void *data,
240              struct wl_output *wl_output,
241              uint32_t flags,
242              int width,
243              int height,
244              int refresh)
245 {
246     Q_UNUSED(data);
247     Q_UNUSED(wl_output);
248     Q_UNUSED(flags);
249     Q_UNUSED(width);
250     Q_UNUSED(height);
251     Q_UNUSED(refresh);
252 }
253
254 const struct wl_output_listener QWaylandDisplay::outputListener = {
255     QWaylandDisplay::outputHandleGeometry,
256     QWaylandDisplay::mode
257 };
258
259 void QWaylandDisplay::waitForScreens()
260 {
261     flushRequests();
262     while (mScreens.isEmpty())
263         blockingReadEvents();
264 }
265
266 void QWaylandDisplay::displayHandleGlobal(struct wl_display *display,
267                                           uint32_t id,
268                                           const char *interface,
269                                           uint32_t version,
270                                           void *data)
271 {
272     Q_UNUSED(display);
273     QWaylandDisplay *that = static_cast<QWaylandDisplay *>(data);
274     that->displayHandleGlobal(id, QByteArray(interface), version);
275 }
276
277 void QWaylandDisplay::displayHandleGlobal(uint32_t id,
278                                           const QByteArray &interface,
279                                           uint32_t version)
280 {
281     Q_UNUSED(version);
282     if (interface == "wl_output") {
283         struct wl_output *output = static_cast<struct wl_output *>(wl_display_bind(mDisplay,id,&wl_output_interface));
284         wl_output_add_listener(output, &outputListener, this);
285     } else if (interface == "wl_compositor") {
286         mCompositor = static_cast<struct wl_compositor *>(wl_display_bind(mDisplay, id,&wl_compositor_interface));
287     } else if (interface == "wl_shm") {
288         mShm = static_cast<struct wl_shm *>(wl_display_bind(mDisplay, id, &wl_shm_interface));
289     } else if (interface == "wl_shell"){
290         mShell = new QWaylandShell(this,id,version);
291     } else if (interface == "wl_input_device") {
292         QWaylandInputDevice *inputDevice =
293             new QWaylandInputDevice(this, id);
294         mInputDevices.append(inputDevice);
295     } else if (interface == "wl_data_device_manager") {
296         mDndSelectionHandler = new QWaylandDataDeviceManager(this, id);
297     } else if (interface == "wl_output_extension") {
298         mOutputExtension = new QWaylandOutputExtension(this,id);
299     } else if (interface == "wl_surface_extension") {
300         mWindowExtension = new QWaylandSurfaceExtension(this,id);
301     } else if (interface == "wl_sub_surface_extension") {
302         mSubSurfaceExtension = new QWaylandSubSurfaceExtension(this,id);
303     } else if (interface == "wl_touch_extension") {
304         mTouchExtension = new QWaylandTouchExtension(this, id);
305     }
306 }
307
308 uint32_t QWaylandDisplay::currentTimeMillisec()
309 {
310     //### we throw away the time information
311     struct timeval tv;
312     int ret = gettimeofday(&tv, 0);
313     if (ret == 0)
314         return tv.tv_sec*1000 + tv.tv_usec/1000;
315     return 0;
316 }
317
318 void QWaylandDisplay::forceRoundTrip()
319 {
320     wl_display_roundtrip(mDisplay);
321 }
322