From d458c31998f5e4fcf85cf31e4b9033fd18f77052 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 17 Jan 2012 15:32:32 +0200 Subject: [PATCH] Implement selection offers from compositor to clients. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit It is a hack but works beautifully. It allows the compositor to participate in copy-paste which becomes mandatory when there is UI running in the compositor process. Change-Id: I1993d8705a26159eff0c9947244b66e954b9f460 Sanity-Review: Qt Sanity Bot Reviewed-by: Jørgen Lind --- src/compositor/wayland_wrapper/wayland_wrapper.pri | 8 ++- src/compositor/wayland_wrapper/wlcompositor.cpp | 3 +- src/compositor/wayland_wrapper/wldatadevice.cpp | 4 +- .../wayland_wrapper/wldatadevicemanager.cpp | 74 +++++++++++++++++++ .../wayland_wrapper/wldatadevicemanager.h | 18 +++++ .../platforms/wayland/qwaylanddataoffer.cpp | 43 ----------- src/plugins/platforms/wayland/qwaylanddataoffer.h | 6 -- .../platforms/wayland/qwaylanddatasource.cpp | 2 +- src/plugins/platforms/wayland/wayland.pro | 9 ++- src/shared/qwaylandmimehelper.cpp | 83 ++++++++++++++++++++++ src/shared/qwaylandmimehelper.h | 55 ++++++++++++++ 11 files changed, 248 insertions(+), 57 deletions(-) create mode 100644 src/shared/qwaylandmimehelper.cpp create mode 100644 src/shared/qwaylandmimehelper.h diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index 4c1f6ee..843f3d6 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -20,7 +20,8 @@ HEADERS += \ $$PWD/wlextendedsurface.h \ $$PWD/wlextendedoutput.h \ $$PWD/wlsubsurface.h \ - $$PWD/wltouch.h + $$PWD/wltouch.h \ + $$PWD/../../shared/qwaylandmimehelper.h SOURCES += \ $$PWD/wlcompositor.cpp \ @@ -37,5 +38,8 @@ SOURCES += \ $$PWD/wlextendedsurface.cpp \ $$PWD/wlextendedoutput.cpp \ $$PWD/wlsubsurface.cpp \ - $$PWD/wltouch.cpp + $$PWD/wltouch.cpp \ + $$PWD/../../shared/qwaylandmimehelper.cpp + +INCLUDEPATH += $$PWD/../../shared diff --git a/src/compositor/wayland_wrapper/wlcompositor.cpp b/src/compositor/wayland_wrapper/wlcompositor.cpp index 3c453d0..23e2252 100644 --- a/src/compositor/wayland_wrapper/wlcompositor.cpp +++ b/src/compositor/wayland_wrapper/wlcompositor.cpp @@ -402,8 +402,7 @@ void Compositor::feedRetainedSelectionData(QMimeData *data) void Compositor::overrideSelection(QMimeData *data) { - Q_UNUSED(data); - // ### TODO implement + m_data_device_manager->overrideSelection(*data); } bool Compositor::isDragging() const diff --git a/src/compositor/wayland_wrapper/wldatadevice.cpp b/src/compositor/wayland_wrapper/wldatadevice.cpp index f4b2f2b..bdabf29 100644 --- a/src/compositor/wayland_wrapper/wldatadevice.cpp +++ b/src/compositor/wayland_wrapper/wldatadevice.cpp @@ -103,7 +103,9 @@ DataDevice::DataDevice(DataDeviceManager *data_device_manager, struct wl_client void DataDevice::sendSelectionFocus() { - //do for all clipboards + if (m_data_device_manager->offerFromCompositorToClient(m_data_device_resource)) + return; + DataSource *source = m_data_device_manager->currentSelectionSource(); if (!source) { return; diff --git a/src/compositor/wayland_wrapper/wldatadevicemanager.cpp b/src/compositor/wayland_wrapper/wldatadevicemanager.cpp index ba8510b..d3e3fb7 100644 --- a/src/compositor/wayland_wrapper/wldatadevicemanager.cpp +++ b/src/compositor/wayland_wrapper/wldatadevicemanager.cpp @@ -45,11 +45,14 @@ #include "wlinputdevice.h" #include "wlcompositor.h" #include "wldataoffer.h" +#include "wlsurface.h" +#include "qwaylandmimehelper.h" #include #include #include #include +#include namespace Wayland { @@ -57,6 +60,7 @@ DataDeviceManager::DataDeviceManager(Compositor *compositor) : m_compositor(compositor) , m_current_selection_source(0) , m_retainedReadNotifier(0) + , m_compositorOwnsSelection(false) { wl_display_add_global(compositor->wl_display(), &wl_data_device_manager_interface, this, DataDeviceManager::bind_func_drag); } @@ -69,6 +73,8 @@ void DataDeviceManager::setCurrentSelectionSource(DataSource *source) return; } + m_compositorOwnsSelection = false; + finishReadFromClient(); m_current_selection_source = source; @@ -210,4 +216,72 @@ struct wl_data_device_manager_interface DataDeviceManager::drag_interface = { DataDeviceManager::get_data_device }; +void DataDeviceManager::overrideSelection(const QMimeData &mimeData) +{ + QStringList formats = mimeData.formats(); + if (formats.isEmpty()) + return; + + m_retainedData.clear(); + foreach (const QString &format, formats) + m_retainedData.setData(format, mimeData.data(format)); + + m_compositor->feedRetainedSelectionData(&m_retainedData); + + m_compositorOwnsSelection = true; + + InputDevice *dev = m_compositor->defaultInputDevice(); + Surface *focusSurface = dev->keyboardFocus(); + if (focusSurface) + offerFromCompositorToClient( + dev->dataDevice(focusSurface->base()->resource.client)->dataDeviceResource()); +} + +bool DataDeviceManager::offerFromCompositorToClient(wl_resource *clientDataDeviceResource) +{ + if (!m_compositorOwnsSelection) + return false; + + wl_client *client = clientDataDeviceResource->client; + qDebug("compositor offers %d types to %p", m_retainedData.formats().count(), client); + + struct wl_resource *selectionOffer = + wl_client_new_object(client, &wl_data_offer_interface, &compositor_offer_interface, this); + wl_resource_post_event(clientDataDeviceResource, WL_DATA_DEVICE_DATA_OFFER, selectionOffer); + foreach (const QString &format, m_retainedData.formats()) { + QByteArray ba = format.toLatin1(); + wl_resource_post_event(selectionOffer, WL_DATA_OFFER_OFFER, ba.constData()); + } + wl_resource_post_event(clientDataDeviceResource, WL_DATA_DEVICE_SELECTION, selectionOffer); + + return true; +} + +void DataDeviceManager::comp_accept(wl_client *, wl_resource *, uint32_t, const char *) +{ +} + +void DataDeviceManager::comp_receive(wl_client *client, wl_resource *resource, const char *mime_type, int32_t fd) +{ + DataDeviceManager *self = static_cast(resource->data); + qDebug("client %p wants data for type %s from compositor", client, mime_type); + QByteArray content = QWaylandMimeHelper::getByteArray(&self->m_retainedData, QString::fromLatin1(mime_type)); + if (!content.isEmpty()) { + QFile f; + if (f.open(fd, QIODevice::WriteOnly)) + f.write(content); + } + close(fd); +} + +void DataDeviceManager::comp_destroy(wl_client *, wl_resource *) +{ +} + +const struct wl_data_offer_interface DataDeviceManager::compositor_offer_interface = { + DataDeviceManager::comp_accept, + DataDeviceManager::comp_receive, + DataDeviceManager::comp_destroy +}; + } //namespace diff --git a/src/compositor/wayland_wrapper/wldatadevicemanager.h b/src/compositor/wayland_wrapper/wldatadevicemanager.h index af26cb0..75844d2 100644 --- a/src/compositor/wayland_wrapper/wldatadevicemanager.h +++ b/src/compositor/wayland_wrapper/wldatadevicemanager.h @@ -71,6 +71,9 @@ public: void sourceDestroyed(DataSource *source); + void overrideSelection(const QMimeData &mimeData); + bool offerFromCompositorToClient(wl_resource *clientDataDeviceResource); + private slots: void readFromClient(int fd); @@ -102,6 +105,21 @@ private: int m_retainedReadIndex; QByteArray m_retainedReadBuf; + bool m_compositorOwnsSelection; + + + static void comp_accept(struct wl_client *client, + struct wl_resource *resource, + uint32_t time, + const char *type); + static void comp_receive(struct wl_client *client, + struct wl_resource *resource, + const char *mime_type, + int32_t fd); + static void comp_destroy(struct wl_client *client, + struct wl_resource *resource); + + static const struct wl_data_offer_interface compositor_offer_interface; }; } diff --git a/src/plugins/platforms/wayland/qwaylanddataoffer.cpp b/src/plugins/platforms/wayland/qwaylanddataoffer.cpp index 0ef52a0..06a550f 100644 --- a/src/plugins/platforms/wayland/qwaylanddataoffer.cpp +++ b/src/plugins/platforms/wayland/qwaylanddataoffer.cpp @@ -40,56 +40,13 @@ ****************************************************************************/ #include "qwaylanddataoffer.h" - #include "qwaylanddatadevicemanager.h" -#include -#include -#include -#include -#include - #include #include #include -QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &mimeType) -{ - QByteArray content; - if (mimeType == QLatin1String("text/plain")) { - content = mimeData->text().toUtf8(); - } else if (mimeData->hasImage() - && (mimeType == QLatin1String("application/x-qt-image") - || mimeType.startsWith("image/"))) { - QImage image = qvariant_cast(mimeData->imageData()); - if (!image.isNull()) { - QBuffer buf; - buf.open(QIODevice::ReadWrite); - QByteArray fmt = "BMP"; - if (mimeType.startsWith("image/")) { - QByteArray imgFmt = mimeType.mid(6).toUpper().toAscii(); - if (QImageWriter::supportedImageFormats().contains(imgFmt)) - fmt = imgFmt; - } - QImageWriter wr(&buf, fmt); - wr.write(image); - content = buf.buffer(); - } - } else if (mimeType == QLatin1String("application/x-color")) { - content = qvariant_cast(mimeData->colorData()).name().toAscii(); - } else if (mimeType == QLatin1String("text/uri-list")) { - QList urls = mimeData->urls(); - for (int i = 0; i < urls.count(); ++i) { - content.append(urls.at(i).toEncoded()); - content.append('\n'); - } - } else { - content = mimeData->data(mimeType); - } - return content; -} - void QWaylandDataOffer::offer_sync_callback(void *data, struct wl_callback *wl_callback, diff --git a/src/plugins/platforms/wayland/qwaylanddataoffer.h b/src/plugins/platforms/wayland/qwaylanddataoffer.h index 26cec39..d51f52d 100644 --- a/src/plugins/platforms/wayland/qwaylanddataoffer.h +++ b/src/plugins/platforms/wayland/qwaylanddataoffer.h @@ -53,12 +53,6 @@ class QWaylandDisplay; -class QWaylandMimeHelper -{ -public: - static QByteArray getByteArray(QMimeData *mimeData, const QString &mimeType); -}; - class QWaylandDataOffer : public QInternalMimeData { public: diff --git a/src/plugins/platforms/wayland/qwaylanddatasource.cpp b/src/plugins/platforms/wayland/qwaylanddatasource.cpp index 8001509..3b3e072 100644 --- a/src/plugins/platforms/wayland/qwaylanddatasource.cpp +++ b/src/plugins/platforms/wayland/qwaylanddatasource.cpp @@ -40,9 +40,9 @@ ****************************************************************************/ #include "qwaylanddatasource.h" - #include "qwaylanddataoffer.h" #include "qwaylandinputdevice.h" +#include "qwaylandmimehelper.h" #include diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index 05fa21f..a3ad15d 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -41,7 +41,8 @@ SOURCES = main.cpp \ qwaylandextendedoutput.cpp \ qwaylandextendedsurface.cpp \ qwaylandsubsurface.cpp \ - qwaylandtouch.cpp + qwaylandtouch.cpp \ + $$PWD/../../../shared/qwaylandmimehelper.cpp HEADERS = qwaylandintegration.h \ qwaylandnativeinterface.h \ @@ -62,9 +63,13 @@ HEADERS = qwaylandintegration.h \ qwaylandextendedoutput.h \ qwaylandextendedsurface.h \ qwaylandsubsurface.h \ - qwaylandtouch.h + qwaylandtouch.h \ + $$PWD/../../../shared/qwaylandmimehelper.h + +INCLUDEPATH += $$PWD/../../../shared INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND + LIBS += $$QMAKE_LIBS_WAYLAND mac { LIBS += -lwayland-client diff --git a/src/shared/qwaylandmimehelper.cpp b/src/shared/qwaylandmimehelper.cpp new file mode 100644 index 0000000..ffdaeef --- /dev/null +++ b/src/shared/qwaylandmimehelper.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandmimehelper.h" +#include +#include +#include +#include +#include + +QByteArray QWaylandMimeHelper::getByteArray(QMimeData *mimeData, const QString &mimeType) +{ + QByteArray content; + if (mimeType == QLatin1String("text/plain")) { + content = mimeData->text().toUtf8(); + } else if (mimeData->hasImage() + && (mimeType == QLatin1String("application/x-qt-image") + || mimeType.startsWith(QLatin1String("image/")))) { + QImage image = qvariant_cast(mimeData->imageData()); + if (!image.isNull()) { + QBuffer buf; + buf.open(QIODevice::ReadWrite); + QByteArray fmt = "BMP"; + if (mimeType.startsWith(QLatin1String("image/"))) { + QByteArray imgFmt = mimeType.mid(6).toUpper().toAscii(); + if (QImageWriter::supportedImageFormats().contains(imgFmt)) + fmt = imgFmt; + } + QImageWriter wr(&buf, fmt); + wr.write(image); + content = buf.buffer(); + } + } else if (mimeType == QLatin1String("application/x-color")) { + content = qvariant_cast(mimeData->colorData()).name().toAscii(); + } else if (mimeType == QLatin1String("text/uri-list")) { + QList urls = mimeData->urls(); + for (int i = 0; i < urls.count(); ++i) { + content.append(urls.at(i).toEncoded()); + content.append('\n'); + } + } else { + content = mimeData->data(mimeType); + } + return content; +} diff --git a/src/shared/qwaylandmimehelper.h b/src/shared/qwaylandmimehelper.h new file mode 100644 index 0000000..f38c74b --- /dev/null +++ b/src/shared/qwaylandmimehelper.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDMIMEHELPER_H +#define QWAYLANDMIMEHELPER_H + +#include +#include +#include + +class QWaylandMimeHelper +{ +public: + static QByteArray getByteArray(QMimeData *mimeData, const QString &mimeType); +}; + +#endif -- 2.7.4