Implement selection offers from compositor to clients.
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>
Tue, 17 Jan 2012 13:32:32 +0000 (15:32 +0200)
committerJørgen Lind <jorgen.lind@nokia.com>
Tue, 17 Jan 2012 16:30:52 +0000 (17:30 +0100)
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 <qt_sanity_bot@ovi.com>
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
src/compositor/wayland_wrapper/wayland_wrapper.pri
src/compositor/wayland_wrapper/wlcompositor.cpp
src/compositor/wayland_wrapper/wldatadevice.cpp
src/compositor/wayland_wrapper/wldatadevicemanager.cpp
src/compositor/wayland_wrapper/wldatadevicemanager.h
src/plugins/platforms/wayland/qwaylanddataoffer.cpp
src/plugins/platforms/wayland/qwaylanddataoffer.h
src/plugins/platforms/wayland/qwaylanddatasource.cpp
src/plugins/platforms/wayland/wayland.pro
src/shared/qwaylandmimehelper.cpp [new file with mode: 0644]
src/shared/qwaylandmimehelper.h [new file with mode: 0644]

index 4c1f6ee..843f3d6 100644 (file)
@@ -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
 
index 3c453d0..23e2252 100644 (file)
@@ -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
index f4b2f2b..bdabf29 100644 (file)
@@ -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;
index ba8510b..d3e3fb7 100644 (file)
 #include "wlinputdevice.h"
 #include "wlcompositor.h"
 #include "wldataoffer.h"
+#include "wlsurface.h"
+#include "qwaylandmimehelper.h"
 
 #include <QtCore/QDebug>
 #include <QtCore/QSocketNotifier>
 #include <fcntl.h>
 #include <QtCore/private/qcore_unix_p.h>
+#include <QtCore/QFile>
 
 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<DataDeviceManager *>(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
index af26cb0..75844d2 100644 (file)
@@ -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;
 };
 
 }
index 0ef52a0..06a550f 100644 (file)
 ****************************************************************************/
 
 #include "qwaylanddataoffer.h"
-
 #include "qwaylanddatadevicemanager.h"
 
-#include <QImage>
-#include <QColor>
-#include <QUrl>
-#include <QBuffer>
-#include <QImageWriter>
-
 #include <QtGui/private/qguiapplication_p.h>
 #include <QtGui/QPlatformClipboard>
 
 #include <QtCore/QDebug>
 
-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<QImage>(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<QColor>(mimeData->colorData()).name().toAscii();
-    } else if (mimeType == QLatin1String("text/uri-list")) {
-        QList<QUrl> 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,
index 26cec39..d51f52d 100644 (file)
 
 class QWaylandDisplay;
 
-class QWaylandMimeHelper
-{
-public:
-    static QByteArray getByteArray(QMimeData *mimeData, const QString &mimeType);
-};
-
 class QWaylandDataOffer : public QInternalMimeData
 {
 public:
index 8001509..3b3e072 100644 (file)
@@ -40,9 +40,9 @@
 ****************************************************************************/
 
 #include "qwaylanddatasource.h"
-
 #include "qwaylanddataoffer.h"
 #include "qwaylandinputdevice.h"
+#include "qwaylandmimehelper.h"
 
 #include <QtCore/QFile>
 
index 05fa21f..a3ad15d 100644 (file)
@@ -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 (file)
index 0000000..ffdaeef
--- /dev/null
@@ -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 <QImage>
+#include <QColor>
+#include <QUrl>
+#include <QBuffer>
+#include <QImageWriter>
+
+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<QImage>(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<QColor>(mimeData->colorData()).name().toAscii();
+    } else if (mimeType == QLatin1String("text/uri-list")) {
+        QList<QUrl> 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 (file)
index 0000000..f38c74b
--- /dev/null
@@ -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 <QString>
+#include <QByteArray>
+#include <QMimeData>
+
+class QWaylandMimeHelper
+{
+public:
+    static QByteArray getByteArray(QMimeData *mimeData, const QString &mimeType);
+};
+
+#endif