1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the Qt Compositor.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
20 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 ** the names of its contributors may be used to endorse or promote
22 ** products derived from this software without specific prior written
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ****************************************************************************/
41 #include "wlcompositor.h"
43 #include "waylandinput.h"
44 #include "wldisplay.h"
45 #include "wlsurface.h"
46 #include "waylandcompositor.h"
47 #include "wldatadevicemanager.h"
48 #include "wldatadevice.h"
49 #include "wlextendedoutput.h"
50 #include "wlextendedsurface.h"
51 #include "wlsubsurface.h"
52 #include "wlshellsurface.h"
55 #include "wlinputdevice.h"
59 #include <QSocketNotifier>
61 #include <qpa/qplatformscreen.h>
62 #include <QGuiApplication>
63 #include <qpa/qplatformscreenpageflipper.h>
75 #include <sys/select.h>
78 #include <wayland-server.h>
80 #include "hardware_integration/graphicshardwareintegration.h"
81 #include "waylandwindowmanagerintegration.h"
85 static Compositor *compositor;
87 void compositor_create_surface(struct wl_client *client,
88 struct wl_resource *resource, uint32_t id)
90 static_cast<Compositor *>(resource->data)->createSurface(client,id);
93 void compositor_create_region(struct wl_client *client,
94 struct wl_resource *compositor, uint32_t id)
97 new Region(client, id);
100 const static struct wl_compositor_interface compositor_interface = {
101 compositor_create_surface,
102 compositor_create_region
105 void Compositor::bind_func(struct wl_client *client, void *data,
106 uint32_t version, uint32_t id)
109 wl_client_add_object(client,&wl_compositor_interface, &compositor_interface, id,data);
113 Compositor *Compositor::instance()
118 Compositor::Compositor(WaylandCompositor *qt_compositor)
119 : m_display(new Display)
120 , m_default_input_device(0)
123 , m_last_queued_buf(-1)
124 , m_qt_compositor(qt_compositor)
125 , m_orientation(Qt::PrimaryOrientation)
126 , m_directRenderSurface(0)
127 , m_directRenderContext(0)
128 , m_directRenderActive(false)
129 #if defined (QT_COMPOSITOR_WAYLAND_GL)
130 , m_graphics_hw_integration(0)
132 , m_outputExtension(0)
133 , m_surfaceExtension(0)
134 , m_subSurfaceExtension(0)
135 , m_touchExtension(0)
140 #if defined (QT_COMPOSITOR_WAYLAND_GL)
141 QWindow *window = qt_compositor->window();
142 if (window && window->surfaceType() != QWindow::RasterSurface)
143 m_graphics_hw_integration = GraphicsHardwareIntegration::createGraphicsHardwareIntegration(qt_compositor);
145 m_windowManagerIntegration = new WindowManagerServerIntegration(qt_compositor, this);
147 wl_display_add_global(m_display->handle(),&wl_compositor_interface,this,Compositor::bind_func);
149 m_data_device_manager = new DataDeviceManager(this);
151 wl_display_add_global(m_display->handle(),&wl_output_interface, &m_output_global,OutputGlobal::output_bind_func);
153 m_shell = new Shell();
154 wl_display_add_global(m_display->handle(), &wl_shell_interface, m_shell, Shell::bind_func);
156 wl_display_init_shm(m_display->handle());
158 m_outputExtension = new OutputExtensionGlobal(this);
159 m_surfaceExtension = new SurfaceExtensionGlobal(this);
160 m_qtkeyExtension = new QtKeyExtensionGlobal(this);
161 m_touchExtension = new TouchExtensionGlobal(this);
163 if (wl_display_add_socket(m_display->handle(), qt_compositor->socketName())) {
164 fprintf(stderr, "Fatal: Failed to open server socket\n");
168 m_loop = wl_display_get_event_loop(m_display->handle());
170 int fd = wl_event_loop_get_fd(m_loop);
172 QSocketNotifier *sockNot = new QSocketNotifier(fd, QSocketNotifier::Read, this);
173 connect(sockNot, SIGNAL(activated(int)), this, SLOT(processWaylandEvents()));
175 qRegisterMetaType<SurfaceBuffer*>("SurfaceBuffer*");
176 //initialize distancefieldglyphcache here
179 Compositor::~Compositor()
182 delete m_outputExtension;
183 delete m_surfaceExtension;
184 delete m_subSurfaceExtension;
185 delete m_touchExtension;
186 delete m_qtkeyExtension;
188 delete m_default_wayland_input_device;
189 delete m_data_device_manager;
191 #ifdef QT_COMPOSITOR_WAYLAND_GL
192 delete m_graphics_hw_integration;
198 void Compositor::frameFinished(Surface *surface)
200 if (surface && m_dirty_surfaces.contains(surface)) {
201 m_dirty_surfaces.remove(surface);
202 surface->sendFrameCallback();
203 } else if (!surface) {
204 QSet<Surface *> dirty = m_dirty_surfaces;
205 m_dirty_surfaces.clear();
206 foreach (Surface *surface, dirty)
207 surface->sendFrameCallback();
211 void Compositor::createSurface(struct wl_client *client, uint32_t id)
213 Surface *surface = new Surface(client,id, this);
215 m_surfaces << surface;
217 m_qt_compositor->surfaceCreated(surface->waylandSurface());
220 struct wl_client *Compositor::getClientFromWinId(uint winId) const
222 Surface *surface = getSurfaceFromWinId(winId);
224 return surface->base()->resource.client;
229 Surface *Compositor::getSurfaceFromWinId(uint winId) const
231 foreach (Surface *surface, m_surfaces) {
232 if (surface->id() == winId)
239 QImage Compositor::image(uint winId) const
241 foreach (Surface *surface, m_surfaces) {
242 if (surface->id() == winId) {
243 return surface->image();
250 uint Compositor::currentTimeMsecs()
252 //### we throw away the time information
254 int ret = gettimeofday(&tv, 0);
256 return tv.tv_sec*1000 + tv.tv_usec/1000;
260 void Compositor::releaseBuffer(SurfaceBuffer *screenBuffer)
262 screenBuffer->scheduledRelease();
265 void Compositor::processWaylandEvents()
267 int ret = wl_event_loop_dispatch(m_loop, 0);
269 fprintf(stderr, "wl_event_loop_dispatch error: %d\n", ret);
272 void Compositor::surfaceDestroyed(Surface *surface)
274 if (defaultInputDevice()->mouseFocus() == surface)
275 defaultInputDevice()->setMouseFocus(0, QPoint(), QPoint());
276 m_surfaces.removeOne(surface);
277 m_dirty_surfaces.remove(surface);
278 if (m_directRenderSurface == surface)
279 setDirectRenderSurface(0, 0);
280 waylandCompositor()->surfaceAboutToBeDestroyed(surface->waylandSurface());
283 void Compositor::markSurfaceAsDirty(Wayland::Surface *surface)
285 m_dirty_surfaces.insert(surface);
288 void Compositor::destroyClient(WaylandClient *c)
290 wl_client *client = static_cast<wl_client *>(c);
292 m_windowManagerIntegration->removeClient(client);
293 wl_client_destroy(client);
297 QWindow *Compositor::window() const
299 return m_qt_compositor->window();
302 GraphicsHardwareIntegration * Compositor::graphicsHWIntegration() const
304 #ifdef QT_COMPOSITOR_WAYLAND_GL
305 return m_graphics_hw_integration;
311 void Compositor::initializeHardwareIntegration()
313 #ifdef QT_COMPOSITOR_WAYLAND_GL
314 if (m_graphics_hw_integration)
315 m_graphics_hw_integration->initializeHardware(m_display);
319 void Compositor::initializeDefaultInputDevice()
321 m_default_wayland_input_device = new WaylandInputDevice(m_qt_compositor);
322 m_default_input_device = m_default_wayland_input_device->handle();
325 void Compositor::initializeWindowManagerProtocol()
327 m_windowManagerIntegration->initialize(m_display);
330 void Compositor::enableSubSurfaceExtension()
332 if (!m_subSurfaceExtension) {
333 m_subSurfaceExtension = new SubSurfaceExtensionGlobal(this);
337 bool Compositor::setDirectRenderSurface(Surface *surface, QOpenGLContext *context)
339 #ifdef QT_COMPOSITOR_WAYLAND_GL
340 if (!m_pageFlipper) {
341 m_pageFlipper = QGuiApplication::primaryScreen()->handle()->pageFlipper();
345 setDirectRenderingActive(false);
347 if (m_graphics_hw_integration && m_graphics_hw_integration->setDirectRenderSurface(surface ? surface->waylandSurface() : 0)) {
348 m_directRenderSurface = surface;
349 m_directRenderContext = context;
358 void Compositor::setDirectRenderingActive(bool active)
360 if (m_directRenderActive == active)
362 m_directRenderActive = active;
365 QMetaObject::invokeMethod(m_pageFlipper, "setDirectRenderingActive", Q_ARG(bool, active));
368 QList<struct wl_client *> Compositor::clients() const
370 QList<struct wl_client *> list;
371 foreach (Surface *surface, m_surfaces) {
372 struct wl_client *client = surface->base()->resource.client;
373 if (!list.contains(client))
379 void Compositor::setScreenOrientation(Qt::ScreenOrientation orientation)
381 m_orientation = orientation;
383 QList<struct wl_client*> clientList = clients();
384 for (int i = 0; i < clientList.length(); ++i) {
385 struct wl_client *client = clientList.at(i);
386 Output *output = m_output_global.outputForClient(client);
388 if (output->extendedOutput()){
389 output->extendedOutput()->sendOutputOrientation(orientation);
394 Qt::ScreenOrientation Compositor::screenOrientation() const
396 return m_orientation;
399 void Compositor::setOutputGeometry(const QRect &geometry)
401 m_output_global.setGeometry(geometry);
404 QRect Compositor::outputGeometry() const
406 return m_output_global.geometry();
409 void Compositor::setOutputRefreshRate(int rate)
411 m_output_global.setRefreshRate(rate);
414 int Compositor::outputRefreshRate() const
416 return m_output_global.refreshRate();
419 void Compositor::setClientFullScreenHint(bool value)
421 m_windowManagerIntegration->setShowIsFullScreen(value);
424 InputDevice* Compositor::defaultInputDevice()
426 return m_default_input_device;
429 QList<Wayland::Surface *> Compositor::surfacesForClient(wl_client *client)
431 QList<Wayland::Surface *> ret;
433 for (int i=0; i < m_surfaces.count(); ++i) {
434 if (m_surfaces.at(i)->base()->resource.client == client) {
435 ret.append(m_surfaces.at(i));
441 void Compositor::configureTouchExtension(int flags)
443 if (m_touchExtension)
444 m_touchExtension->setFlags(flags);
447 void Compositor::setRetainedSelectionWatcher(RetainedSelectionFunc func, void *param)
449 m_retainNotify = func;
450 m_retainNotifyParam = param;
453 bool Compositor::wantsRetainedSelection() const
455 return m_retainNotify != 0;
458 void Compositor::feedRetainedSelectionData(QMimeData *data)
460 if (m_retainNotify) {
461 m_retainNotify(data, m_retainNotifyParam);
465 void Compositor::scheduleReleaseBuffer(SurfaceBuffer *screenBuffer)
467 QMetaObject::invokeMethod(this,"releaseBuffer",Q_ARG(SurfaceBuffer*,screenBuffer));
470 void Compositor::overrideSelection(QMimeData *data)
472 m_data_device_manager->overrideSelection(*data);
475 bool Compositor::isDragging() const
480 void Compositor::sendDragMoveEvent(const QPoint &global, const QPoint &local,
486 // Drag::instance()->dragMove(global, local, surface);
489 void Compositor::sendDragEndEvent()
491 // Drag::instance()->dragEnd();
494 } // namespace Wayland