diff options
Diffstat (limited to 'src/compositor/compositor_api/qwaylandcompositor.cpp')
-rw-r--r-- | src/compositor/compositor_api/qwaylandcompositor.cpp | 840 |
1 files changed, 637 insertions, 203 deletions
diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 04d1c4aed..a431cdde8 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -4,367 +4,801 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the Qt Compositor. +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwaylandcompositor.h" +#include "qwaylandcompositor_p.h" + +#include <QtWaylandCompositor/qwaylandclient.h> +#include <QtWaylandCompositor/qwaylandinput.h> +#include <QtWaylandCompositor/qwaylandoutput.h> +#include <QtWaylandCompositor/qwaylandview.h> +#include <QtWaylandCompositor/qwaylandclient.h> +#include <QtWaylandCompositor/qwaylandkeyboard.h> +#include <QtWaylandCompositor/qwaylandpointer.h> +#include <QtWaylandCompositor/qwaylandtouch.h> -#include "qwaylandclient.h" -#include "qwaylandinput.h" -#include "qwaylandoutput.h" -#include "qwaylandglobalinterface.h" -#include "qwaylandsurfaceview.h" +#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h> +#include <QtWaylandCompositor/private/qwaylandsurface_p.h> -#include "wayland_wrapper/qwlcompositor_p.h" #include "wayland_wrapper/qwldatadevice_p.h" -#include "wayland_wrapper/qwlsurface_p.h" -#include "wayland_wrapper/qwlinputdevice_p.h" -#include "wayland_wrapper/qwlinputpanel_p.h" -#include "wayland_wrapper/qwlshellsurface_p.h" +#include "wayland_wrapper/qwldatadevicemanager_p.h" + +#include "hardware_integration/qwlclientbufferintegration_p.h" +#include "hardware_integration/qwlclientbufferintegrationfactory_p.h" +#include "hardware_integration/qwlserverbufferintegration_p.h" +#include "hardware_integration/qwlserverbufferintegrationfactory_p.h" +#include "hardware_integration/qwlhwintegration_p.h" + +#include "extensions/qwaylandwindowmanagerextension.h" + +#include "qwaylandxkb.h" +#include "qwaylandshmformathelper.h" #include <QtCore/QCoreApplication> #include <QtCore/QStringList> +#include <QtCore/QSocketNotifier> #include <QtGui/QDesktopServices> #include <QtGui/QScreen> -#include <QDebug> +#include <QtGui/qpa/qwindowsysteminterface_p.h> +#include <QtGui/qpa/qplatformnativeinterface.h> +#include <QtGui/private/qguiapplication_p.h> QT_BEGIN_NAMESPACE -QWaylandCompositor::QWaylandCompositor(const char *socketName, ExtensionFlags extensions) - : m_compositor(new QtWayland::Compositor(this, extensions)) +namespace QtWayland { + +class WindowSystemEventHandler : public QWindowSystemEventHandler { - m_compositor->m_socket_name = socketName; - m_compositor->init(); -} +public: + WindowSystemEventHandler(QWaylandCompositor *c) : compositor(c) {} + bool sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) Q_DECL_OVERRIDE + { + if (e->type == QWindowSystemInterfacePrivate::Key) { + QWindowSystemInterfacePrivate::KeyEvent *ke = static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e); + QWaylandKeyboardPrivate *keyb = QWaylandKeyboardPrivate::get(compositor->defaultInputDevice()->keyboard()); + + uint32_t code = ke->nativeScanCode; + bool isDown = ke->keyType == QEvent::KeyPress; + +#ifndef QT_NO_WAYLAND_XKB + QString text; + Qt::KeyboardModifiers modifiers = QWaylandXkb::modifiers(keyb->xkbState()); + + const xkb_keysym_t sym = xkb_state_key_get_one_sym(keyb->xkbState(), code); + uint utf32 = xkb_keysym_to_utf32(sym); + if (utf32) + text = QString::fromUcs4(&utf32, 1); + int qtkey = QWaylandXkb::keysymToQtKey(sym, modifiers, text); + + ke->key = qtkey; + ke->modifiers = modifiers; + ke->nativeVirtualKey = sym; + ke->nativeModifiers = keyb->xkbModsMask(); + ke->unicode = text; +#endif + if (!ke->repeat) + keyb->keyEvent(code, isDown ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED); -QWaylandCompositor::QWaylandCompositor(const char *socketName, QtWayland::Compositor *dptr) - : m_compositor(dptr) + QWindowSystemEventHandler::sendEvent(e); + + if (!ke->repeat) { + keyb->updateKeymap(); + keyb->updateModifierState(code, isDown ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED); + } + } else { + QWindowSystemEventHandler::sendEvent(e); + } + return true; + } + + QWaylandCompositor *compositor; +}; + +} // namespace + +QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *compositor) + : display(0) +#if defined (QT_COMPOSITOR_WAYLAND_GL) + , use_hw_integration_extension(true) + , client_buffer_integration(0) + , server_buffer_integration(0) +#endif + , retainSelection(false) + , initialized(false) { - m_compositor->m_socket_name = socketName; - m_compositor->init(); + display = static_cast<wl_display*>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("server_wl_display")); + if (!display) + display = wl_display_create(); + eventHandler.reset(new QtWayland::WindowSystemEventHandler(compositor)); + timer.start(); + + QWindowSystemInterfacePrivate::installWindowSystemEventHandler(eventHandler.data()); } -QWaylandCompositor::~QWaylandCompositor() +void QWaylandCompositorPrivate::init() { - qDeleteAll(m_compositor->m_globals); - delete m_compositor; + Q_Q(QWaylandCompositor); + QStringList arguments = QCoreApplication::instance()->arguments(); + + int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name")); + if (socketArg != -1 && socketArg + 1 < arguments.size()) + socket_name = arguments.at(socketArg + 1).toLocal8Bit(); + + wl_compositor::init(display, 3); + + data_device_manager = new QtWayland::DataDeviceManager(q); + + wl_display_init_shm(display); + QVector<wl_shm_format> formats = QWaylandShmFormatHelper::supportedWaylandFormats(); + foreach (wl_shm_format format, formats) + wl_display_add_shm_format(display, format); + + const char *socketName = 0; + if (socket_name.size()) + socketName = socket_name.constData(); + if (wl_display_add_socket(display, socketName)) { + qFatal("Fatal: Failed to open server socket\n"); + } + + loop = wl_display_get_event_loop(display); + + int fd = wl_event_loop_get_fd(loop); + + QSocketNotifier *sockNot = new QSocketNotifier(fd, QSocketNotifier::Read, q); + QObject::connect(sockNot, SIGNAL(activated(int)), q, SLOT(processWaylandEvents())); + + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + QObject::connect(dispatcher, SIGNAL(aboutToBlock()), q, SLOT(processWaylandEvents())); + + initializeHardwareIntegration(); + initializeDefaultInputDevice(); + + initialized = true; + + Q_FOREACH (QPointer<QObject> object, polish_objects) { + if (object) { + QEvent polishEvent(QEvent::Polish); + QCoreApplication::sendEvent(object.data(), &polishEvent); + } + } } -void QWaylandCompositor::addGlobalInterface(QWaylandGlobalInterface *interface) +QWaylandCompositorPrivate::~QWaylandCompositorPrivate() { - wl_global_create(m_compositor->wl_display(), interface->interface(), interface->version(), interface, QtWayland::Compositor::bindGlobal); - m_compositor->m_globals << interface; + qDeleteAll(clients); + + qDeleteAll(outputs); + + delete data_device_manager; + + wl_display_destroy(display); } -void QWaylandCompositor::addDefaultShell() +void QWaylandCompositorPrivate::destroySurface(QWaylandSurface *surface) { - addGlobalInterface(new QtWayland::Shell); + Q_Q(QWaylandCompositor); + q->surfaceAboutToBeDestroyed(surface); + + delete surface; } -struct wl_display *QWaylandCompositor::waylandDisplay() const +void QWaylandCompositorPrivate::unregisterSurface(QWaylandSurface *surface) { - return m_compositor->wl_display(); + if (!all_surfaces.removeOne(surface)) + qWarning("%s Unexpected state. Cant find registered surface\n", Q_FUNC_INFO); } -void QWaylandCompositor::sendFrameCallbacks(QList<QWaylandSurface *> visibleSurfaces) +void QWaylandCompositorPrivate::feedRetainedSelectionData(QMimeData *data) { - m_compositor->sendFrameCallbacks(visibleSurfaces); + Q_Q(QWaylandCompositor); + if (retainSelection) + q->retainedSelectionReceived(data); } -void QWaylandCompositor::frameStarted() +void QWaylandCompositorPrivate::addPolishObject(QObject *object) { - foreach (QtWayland::Surface *surf, m_compositor->surfaces()) - surf->frameStarted(); + if (initialized) { + QCoreApplication::postEvent(object, new QEvent(QEvent::Polish)); + } else { + polish_objects.append(object); + } } -void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface) +/*! + \qmlsignal void QtWaylandCompositor::WaylandCompositor::createSurface(object client, int id, int version) + + This signal is emitted when a client has created a surface. + The slot connecting to this signal may create and initialize + a WaylandSurface instance in the scope of the slot. + Otherwise a default surface is created. +*/ + +/*! + \fn void QWaylandCompositor::createSurface(QWaylandClient *client, uint id, int version) + + This signal is emitted when a client has created a surface. + The slot connecting to this signal may create and initialize + a QWaylandSurface instance in the scope of the slot. + Otherwise a default surface is created. + + Connections to this signal must be of Qt::DirectConnection connection type. +*/ + +/* + \qmlsignal void surfaceCreated(QWaylandSurface *surface) + + This signal is emitted when a new WaylandSurface instance has been created. +*/ + +/* + \fn void surfaceCreated(QWaylandSurface *surface) + + This signal is emitted when a new QWaylandSurface instance has been created. +*/ + + +void QWaylandCompositorPrivate::compositor_create_surface(Resource *resource, uint32_t id) { - destroyClient(surface->client()); + Q_Q(QWaylandCompositor); + QWaylandClient *client = QWaylandClient::fromWlClient(q, resource->client()); + emit q->createSurface(client, id, resource->version()); +#ifndef QT_NO_DEBUG + Q_ASSERT_X(!QWaylandSurfacePrivate::hasUninitializedSurface(), "QWaylandCompositor", QStringLiteral("Found uninitialized QWaylandSurface after emitting QWaylandCompositor::createSurface for id %1. All surfaces has to be initialized immediately after creation. See QWaylandSurface::initialize.").arg(id).toLocal8Bit().constData()); +#endif + struct wl_resource *surfResource = wl_client_get_object(client->client(), id); + + QWaylandSurface *surface; + if (surfResource) { + surface = QWaylandSurface::fromResource(surfResource); + } else { + surface = createDefaultSurface(); + surface->initialize(q, client, id, resource->version()); + } + Q_ASSERT(surface); + all_surfaces.append(surface); + emit q->surfaceCreated(surface); } -void QWaylandCompositor::destroyClient(QWaylandClient *client) +void QWaylandCompositorPrivate::compositor_create_region(Resource *resource, uint32_t id) { - m_compositor->destroyClient(client); + new QtWayland::Region(resource->client(), id); } -QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* client) const +/*! + \internal + Used to create a fallback QWaylandSurface when no surface was + created by emitting the QWaylandCompositor::createSurface signal. +*/ +QWaylandSurface *QWaylandCompositorPrivate::createDefaultSurface() { - QList<QtWayland::Surface *> surfaces = m_compositor->surfaces(); + return new QWaylandSurface(); +} - QList<QWaylandSurface *> result; - for (int i = 0; i < surfaces.count(); ++i) { - if (surfaces.at(i)->waylandSurface()->client() == client) { - result.append(surfaces.at(i)->waylandSurface()); - } - } +void QWaylandCompositorPrivate::initializeHardwareIntegration() +{ +#ifdef QT_COMPOSITOR_WAYLAND_GL + Q_Q(QWaylandCompositor); + if (use_hw_integration_extension) + hw_integration.reset(new QtWayland::HardwareIntegration(q)); + + loadClientBufferIntegration(); + loadServerBufferIntegration(); - return result; + if (client_buffer_integration) + client_buffer_integration->initializeHardware(display); + if (server_buffer_integration) + server_buffer_integration->initializeHardware(q); +#endif } -QList<QWaylandSurface *> QWaylandCompositor::surfaces() const +void QWaylandCompositorPrivate::initializeDefaultInputDevice() { - QList<QtWayland::Surface *> surfaces = m_compositor->surfaces(); - QList<QWaylandSurface *> surfs; - surfs.reserve(surfaces.count()); - foreach (QtWayland::Surface *s, surfaces) - surfs << s->waylandSurface(); - return surfs; + Q_Q(QWaylandCompositor); + inputDevices.append(q->createInputDevice()); + q->defaultInputDeviceChanged(); } -QList<QWaylandOutput *> QWaylandCompositor::outputs() const +void QWaylandCompositorPrivate::loadClientBufferIntegration() { - return m_compositor->outputs(); +#ifdef QT_COMPOSITOR_WAYLAND_GL + Q_Q(QWaylandCompositor); + QStringList keys = QtWayland::ClientBufferIntegrationFactory::keys(); + QString targetKey; + QByteArray clientBufferIntegration = qgetenv("QT_WAYLAND_HARDWARE_INTEGRATION"); + if (clientBufferIntegration.isEmpty()) + clientBufferIntegration = qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION"); + if (keys.contains(QString::fromLocal8Bit(clientBufferIntegration.constData()))) { + targetKey = QString::fromLocal8Bit(clientBufferIntegration.constData()); + } else if (keys.contains(QString::fromLatin1("wayland-egl"))) { + targetKey = QString::fromLatin1("wayland-egl"); + } else if (!keys.isEmpty()) { + targetKey = keys.first(); + } + + if (!targetKey.isEmpty()) { + client_buffer_integration.reset(QtWayland::ClientBufferIntegrationFactory::create(targetKey, QStringList())); + if (client_buffer_integration) { + client_buffer_integration->setCompositor(q); + if (hw_integration) + hw_integration->setClientBufferIntegration(targetKey); + } + } + //BUG: if there is no client buffer integration, bad things will happen when opengl is used +#endif } -QWaylandOutput *QWaylandCompositor::output(QWindow *window) +void QWaylandCompositorPrivate::loadServerBufferIntegration() { - return m_compositor->output(window); +#ifdef QT_COMPOSITOR_WAYLAND_GL + QStringList keys = QtWayland::ServerBufferIntegrationFactory::keys(); + QString targetKey; + QByteArray serverBufferIntegration = qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"); + if (keys.contains(QString::fromLocal8Bit(serverBufferIntegration.constData()))) { + targetKey = QString::fromLocal8Bit(serverBufferIntegration.constData()); + } + if (!targetKey.isEmpty()) { + server_buffer_integration.reset(QtWayland::ServerBufferIntegrationFactory::create(targetKey, QStringList())); + if (hw_integration) + hw_integration->setServerBufferIntegration(targetKey); + } +#endif } -QWaylandOutput *QWaylandCompositor::primaryOutput() const +/*! + \qmltype WaylandCompositor + \inqmlmodule QtWayland.Compositor + \brief Type managing the Wayland display server. + + The WaylandCompositor manages the connections to the clients, as well as the different + \l{WaylandOutput}{outputs} and \l{WaylandInput}{input devices}. + + Normally, a compositor application will have a single WaylandCompositor + instance, which can have several outputs as children. When a client + requests the compositor to create a surface, the request is handled by + the onCreateSurface handler. + + Extensions that are supported by the compositor should be instantiated and added to the + extensions property. +*/ + + +/*! + \class QWaylandCompositor + \inmodule QtWaylandCompositor + \brief Class managing the Wayland display server. + + The QWaylandCompositor manages the connections to the clients, as well as the different \l{QWaylandOutput}{outputs} + and \l{QWaylandInput}{input devices}. + + Normally, a compositor application will have a single WaylandCompositor + instance, which can have several outputs as children. +*/ + +/*! + * Constructs a QWaylandCompositor with the given \a parent. + */ +QWaylandCompositor::QWaylandCompositor(QObject *parent) + : QWaylandObject(*new QWaylandCompositorPrivate(this), parent) { - return m_compositor->primaryOutput(); } -void QWaylandCompositor::setPrimaryOutput(QWaylandOutput *output) +/*! + * \internal + * Constructs a QWaylandCompositor with the private object \a dptr and \a parent. + */ +QWaylandCompositor::QWaylandCompositor(QWaylandCompositorPrivate &dptr, QObject *parent) + : QWaylandObject(dptr, parent) { - m_compositor->setPrimaryOutput(output); } -void QWaylandCompositor::cleanupGraphicsResources() +/*! + * Destroys the QWaylandCompositor + */ +QWaylandCompositor::~QWaylandCompositor() { - m_compositor->cleanupGraphicsResources(); } -void QWaylandCompositor::surfaceAboutToBeDestroyed(QWaylandSurface *surface) +/*! + * Initializes the QWaylandCompositor. + * If you override this function in your subclass, be sure to call the base class implementation. + */ +void QWaylandCompositor::create() { - Q_UNUSED(surface); + Q_D(QWaylandCompositor); + d->init(); } -QWaylandSurfaceView *QWaylandCompositor::pickView(const QPointF &globalPosition) const +/*! + * Returns true if the QWaylandCompositor has been initialized. Otherwise returns false. + */ +bool QWaylandCompositor::isCreated() const { - Q_FOREACH (QWaylandOutput *output, outputs()) { - // Skip coordinates not in output - if (!QRectF(output->geometry()).contains(globalPosition)) - continue; + Q_D(const QWaylandCompositor); + return d->initialized; +} - Q_FOREACH (QWaylandSurface *surface, output->surfaces()) { - Q_FOREACH (QWaylandSurfaceView *view, surface->views()) { - if (QRectF(view->pos(), surface->size()).contains(globalPosition)) - return view; - } - } - } +/*! + * \qmlproperty string QtWaylandCompositor::WaylandCompositor::socketName + * + * This property holds the socket name used by WaylandCompositor to communicate with + * clients. It must be set before the component is completed. + * + * If the socketName is empty (the default), the contents of the environment + * variable WAYLAND_DISPLAY is used instead. If this is not set, the + * default "wayland-0" is used. + */ - return Q_NULLPTR; +/*! + * \property QWaylandCompositor::socketName + * + * This property holds the socket name used by QWaylandCompositor to communicate with + * clients. This must be set before the QWaylandCompositor is \l{create()}{created}. + * + * If the socketName is empty (the default), the contents of the environment + * variable WAYLAND_DISPLAY is used instead. If this is not set, the + * default "wayland-0" is used. + */ +void QWaylandCompositor::setSocketName(const QByteArray &name) +{ + Q_D(QWaylandCompositor); + if (d->initialized) { + qWarning("%s: Changing socket name after initializing the compositor is not supported.\n", Q_FUNC_INFO); + return; + } + d->socket_name = name; } -QPointF QWaylandCompositor::mapToView(QWaylandSurfaceView *surface, const QPointF &globalPosition) const +QByteArray QWaylandCompositor::socketName() const { - return globalPosition - surface->pos(); + Q_D(const QWaylandCompositor); + return d->socket_name; } /*! - Override this to handle QDesktopServices::openUrl() requests from the clients. - - The default implementation simply forwards the request to QDesktopServices::openUrl(). -*/ -bool QWaylandCompositor::openUrl(QWaylandClient *client, const QUrl &url) + * \internal + */ +struct wl_display *QWaylandCompositor::display() const { - Q_UNUSED(client); - return QDesktopServices::openUrl(url); + Q_D(const QWaylandCompositor); + return d->display; } -QtWayland::Compositor * QWaylandCompositor::handle() const +/*! + * \internal + */ +uint32_t QWaylandCompositor::nextSerial() { - return m_compositor; + Q_D(QWaylandCompositor); + return wl_display_next_serial(d->display); } -void QWaylandCompositor::setRetainedSelectionEnabled(bool enabled) +/*! + * \internal + */ +QList<QWaylandClient *>QWaylandCompositor::clients() const { - m_compositor->setRetainedSelectionEnabled(enabled); + Q_D(const QWaylandCompositor); + return d->clients; } -bool QWaylandCompositor::retainedSelectionEnabled() const +/*! + * \qmlmethod QtWaylandCompositor::WaylandCompositor::destroyClientForSurface(surface) + * + * Destroys the client for the WaylandSurface \a surface. + */ + +/*! + * Destroys the client for the \a surface. + */ +void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface) { - return m_compositor->retainedSelectionEnabled(); + destroyClient(surface->client()); } -void QWaylandCompositor::retainedSelectionReceived(QMimeData *) +/*! + * \qmlmethod QtWaylandCompositor::WaylandCompositor::destroyClient(client) + * + * Destroys the given WaylandClient \a client. + */ + +/*! + * Destroys the \a client. + */ +void QWaylandCompositor::destroyClient(QWaylandClient *client) { + if (!client) + return; + + QWaylandWindowManagerExtension *wmExtension = QWaylandWindowManagerExtension::findIn(this); + if (wmExtension) + wmExtension->sendQuitMessage(client->client()); + + wl_client_destroy(client->client()); } -void QWaylandCompositor::overrideSelection(const QMimeData *data) +/*! + * \internal + */ +QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* client) const { - m_compositor->overrideSelection(data); + Q_D(const QWaylandCompositor); + QList<QWaylandSurface *> surfs; + foreach (QWaylandSurface *surface, d->all_surfaces) { + if (surface->client() == client) + surfs.append(surface); + } + return surfs; } -void QWaylandCompositor::setClientFullScreenHint(bool value) +/*! + * \internal + */ +QList<QWaylandSurface *> QWaylandCompositor::surfaces() const { - m_compositor->setClientFullScreenHint(value); + Q_D(const QWaylandCompositor); + return d->all_surfaces; } -const char *QWaylandCompositor::socketName() const -{ - if (m_compositor->m_socket_name.isEmpty()) - return 0; - return m_compositor->m_socket_name.constData(); +/*! + * Returns the QWaylandOutput that is connected to the given \a window. + */ +QWaylandOutput *QWaylandCompositor::outputFor(QWindow *window) const +{ + Q_D(const QWaylandCompositor); + foreach (QWaylandOutput *output, d->outputs) { + if (output->window() == window) + return output; + } + + return Q_NULLPTR; } -#if QT_DEPRECATED_SINCE(5, 5) /*! - Set the screen orientation based on accelerometer data or similar. -*/ -void QWaylandCompositor::setScreenOrientation(Qt::ScreenOrientation orientation) + * \qmlproperty object QtWaylandCompositor::WaylandCompositor::defaultOutput + * + * This property contains the first in the list of outputs added to the + * WaylandCompositor, or null if no outputs have been added. + * + * Setting a new default output prepends it to the output list, making + * it the new default, but the previous default is not removed from + * the list. + */ +/*! + * \property QWaylandCompositor::defaultOutput + * + * This property contains the first in the list of outputs added to the + * QWaylandCompositor, or null if no outputs have been added. + * + * Setting a new default output prepends it to the output list, making + * it the new default, but the previous default is not removed from + * the list. If the new default output was already in the list of outputs, + * it is moved to the beginning of the list. + */ +QWaylandOutput *QWaylandCompositor::defaultOutput() const { - QWaylandOutput *output = primaryOutput(); - if (output) { - bool isPortrait = output->window()->screen()->primaryOrientation() == Qt::PortraitOrientation; - - switch (orientation) { - case Qt::PrimaryOrientation: - output->setTransform(QWaylandOutput::TransformNormal); - break; - case Qt::LandscapeOrientation: - output->setTransform(isPortrait ? QWaylandOutput::Transform270 : QWaylandOutput::TransformNormal); - break; - case Qt::PortraitOrientation: - output->setTransform(isPortrait ? QWaylandOutput::TransformNormal : QWaylandOutput::Transform90); - break; - case Qt::InvertedLandscapeOrientation: - output->setTransform(isPortrait ? QWaylandOutput::Transform90 : QWaylandOutput::Transform180); - break; - case Qt::InvertedPortraitOrientation: - output->setTransform(isPortrait ? QWaylandOutput::Transform180 : QWaylandOutput::Transform270); - break; - } - } + Q_D(const QWaylandCompositor); + return d->defaultOutput(); } -void QWaylandCompositor::setOutputGeometry(const QRect &geometry) +void QWaylandCompositor::setDefaultOutput(QWaylandOutput *output) { - QWaylandOutput *output = primaryOutput(); - if (output) - output->setGeometry(geometry); + Q_D(QWaylandCompositor); + if (d->outputs.size() && d->outputs.first() == output) + return; + d->outputs.removeOne(output); + d->outputs.prepend(output); + defaultOutputChanged(); } -QRect QWaylandCompositor::outputGeometry() const +/*! + * \internal + */ +QList<QWaylandOutput *> QWaylandCompositor::outputs() const { - QWaylandOutput *output = primaryOutput(); - if (output) - return output->geometry(); - return QRect(); + Q_D(const QWaylandCompositor); + return d->outputs; } -void QWaylandCompositor::setOutputRefreshRate(int rate) +/*! + * \internal + */ +uint QWaylandCompositor::currentTimeMsecs() const { - QWaylandOutput *output = primaryOutput(); - if (output) - output->setMode({output->mode().size, rate}); + Q_D(const QWaylandCompositor); + return d->timer.elapsed(); } -int QWaylandCompositor::outputRefreshRate() const +/*! + * \internal + */ +void QWaylandCompositor::processWaylandEvents() { - QWaylandOutput *output = primaryOutput(); - if (output) - return output->mode().refreshRate; - return 0; + Q_D(QWaylandCompositor); + int ret = wl_event_loop_dispatch(d->loop, 0); + if (ret) + fprintf(stderr, "wl_event_loop_dispatch error: %d\n", ret); + wl_display_flush_clients(d->display); } -#endif -QWaylandInputDevice *QWaylandCompositor::defaultInputDevice() const +/*! + * \internal + */ +QWaylandInputDevice *QWaylandCompositor::createInputDevice() { - return m_compositor->defaultInputDevice()->handle(); + return new QWaylandInputDevice(this); } -QWaylandInputPanel *QWaylandCompositor::inputPanel() const +/*! + * \internal + */ +QWaylandPointer *QWaylandCompositor::createPointerDevice(QWaylandInputDevice *inputDevice) { - return m_compositor->inputPanel()->handle(); + return new QWaylandPointer(inputDevice); } -QWaylandDrag *QWaylandCompositor::drag() const +/*! + * \internal + */ +QWaylandKeyboard *QWaylandCompositor::createKeyboardDevice(QWaylandInputDevice *inputDevice) { - return m_compositor->defaultInputDevice()->dragHandle(); + return new QWaylandKeyboard(inputDevice); } -bool QWaylandCompositor::isDragging() const +/*! + * \internal + */ +QWaylandTouch *QWaylandCompositor::createTouchDevice(QWaylandInputDevice *inputDevice) { - return m_compositor->isDragging(); + return new QWaylandTouch(inputDevice); } -void QWaylandCompositor::sendDragMoveEvent(const QPoint &global, const QPoint &local, - QWaylandSurface *surface) +/*! + * \qmlproperty bool QtWaylandCompositor::WaylandCompositor::retainedSelection + * + * This property holds whether retained selection is enabled. + */ + +/*! + * \property QWaylandCompositor::retainedSelection + * + * This property holds whether retained selection is enabled. + */ +void QWaylandCompositor::setRetainedSelectionEnabled(bool enabled) { - m_compositor->sendDragMoveEvent(global, local, surface ? surface->handle() : 0); + Q_D(QWaylandCompositor); + d->retainSelection = enabled; } -void QWaylandCompositor::sendDragEndEvent() +bool QWaylandCompositor::retainedSelectionEnabled() const { - m_compositor->sendDragEndEvent(); + Q_D(const QWaylandCompositor); + return d->retainSelection; } -void QWaylandCompositor::setCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY) +/*! + * \internal + */ +void QWaylandCompositor::retainedSelectionReceived(QMimeData *) { - Q_UNUSED(surface); - Q_UNUSED(hotspotX); - Q_UNUSED(hotspotY); } -void QWaylandCompositor::configureTouchExtension(TouchExtensionFlags flags) +/*! + * \internal + */ +void QWaylandCompositor::overrideSelection(const QMimeData *data) { - m_compositor->configureTouchExtension(flags); + Q_D(QWaylandCompositor); + d->data_device_manager->overrideSelection(*data); } -QWaylandSurfaceView *QWaylandCompositor::createView(QWaylandSurface *surface) +/*! + * \qmlproperty object QtWaylandCompositor::WaylandCompositor::defaultInputDevice + * + * This property contains the default input device for this + * WaylandCompositor. + */ + +/*! + * \property QWaylandCompositor::defaultInputDevice + * + * This property contains the default input device for this + * QWaylandCompositor. + */ +QWaylandInputDevice *QWaylandCompositor::defaultInputDevice() const { - return new QWaylandSurfaceView(surface); + Q_D(const QWaylandCompositor); + if (d->inputDevices.size()) + return d->inputDevices.first(); + return Q_NULLPTR; } +/*! + * \internal + * + * Currently, Qt only supports a single input device, so this exists for + * future proofing the APIs. + */ QWaylandInputDevice *QWaylandCompositor::inputDeviceFor(QInputEvent *inputEvent) { - return m_compositor->inputDeviceFor(inputEvent); + Q_D(QWaylandCompositor); + QWaylandInputDevice *dev = NULL; + for (int i = 0; i < d->inputDevices.size(); i++) { + QWaylandInputDevice *candidate = d->inputDevices.at(i); + if (candidate->isOwner(inputEvent)) { + dev = candidate; + break; + } + } + return dev; } -QWaylandOutput *QWaylandCompositor::createOutput(QWindow *window, - const QString &manufacturer, - const QString &model) +/*! + * \qmlproperty bool QtWaylandCompositor::WaylandCompositor::useHardwareIntegrationExtension + * + * This property holds whether the hardware integration extension should be enabled for + * this WaylandCompositor. + * + * This property must be set before the compositor component is completed. + */ + +/*! + * \property QWaylandCompositor::useHardwareIntegrationExtension + * + * This property holds whether the hardware integration extension should be enabled for + * this QWaylandCompositor. + * + * This property must be set before the compositor is \l{create()}{created}. + */ +bool QWaylandCompositor::useHardwareIntegrationExtension() const { - return new QWaylandOutput(this, window, manufacturer, model); + Q_D(const QWaylandCompositor); + return d->use_hw_integration_extension; +} + +void QWaylandCompositor::setUseHardwareIntegrationExtension(bool use) +{ + Q_D(QWaylandCompositor); + if (use == d->use_hw_integration_extension) + return; + + if (d->initialized) + qWarning("Setting QWaylandCompositor::useHardwareIntegrationExtension after initialization has no effect"); + + d->use_hw_integration_extension = use; + useHardwareIntegrationExtensionChanged(); } QT_END_NAMESPACE |