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 plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qwaylanddatadevicemanager.h"
44 #include "qwaylandinputdevice.h"
45 #include "qwaylanddataoffer.h"
46 #include "qwaylanddatasource.h"
47 #include "qwaylandshmbackingstore.h"
49 #include <wayland-client-protocol.h>
50 #include <wayland-client.h>
52 #include <QtGui/QGuiApplication>
53 #include <QtGui/private/qguiapplication_p.h>
54 #include <qpa/qplatformclipboard.h>
55 #include <QtGui/QPainter>
57 #include <QWindowSystemInterface>
59 #include <QtCore/QDebug>
61 void QWaylandDataDeviceManager::data_offer(void *data,
62 struct wl_data_device *data_device,
66 QWaylandDataDeviceManager *handler = static_cast<QWaylandDataDeviceManager *>(data);
67 //this will be hidden with a wl function call in the near future I hope, but I suppose the scanner
68 //doesn't support it yet
69 struct wl_proxy *newId = wl_proxy_create_for_id(reinterpret_cast<struct wl_proxy *>(data_device),
70 id, &wl_data_offer_interface);
71 struct wl_data_offer *data_offer =
72 reinterpret_cast<struct wl_data_offer *>(newId);
75 new QWaylandDataOffer(handler->display(),data_offer);
78 void QWaylandDataDeviceManager::enter(void *data,
79 struct wl_data_device *wl_data_device,
81 struct wl_surface *surface,
84 struct wl_data_offer *id)
87 Q_UNUSED(wl_data_device);
90 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
91 if (time < data_device_manager->m_drag_last_event_time)
93 data_device_manager->m_drag_last_event_time = time;
95 data_device_manager->m_drag_current_event_window = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface));
98 QWaylandDataOffer *offer = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
102 // QPoint point(x,y);
103 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
104 // QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),
105 // offer,point,allActions);
106 // data_device_manager->m_drag_can_drop = response.accepted();
107 data_device_manager->m_drag_data_offer = offer;
108 if (data_device_manager->m_drag_can_drop) {
109 const char *first_offer = qPrintable(offer->formats_sys().at(0));
110 wl_data_offer_accept(offer->handle(),QWaylandDisplay::currentTimeMillisec(),first_offer);
112 wl_data_offer_accept(offer->handle(),QWaylandDisplay::currentTimeMillisec(),0);
116 void QWaylandDataDeviceManager::leave(void *data,
117 struct wl_data_device *wl_data_device)
119 Q_UNUSED(wl_data_device);
120 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
121 // QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),0,QPoint(0,0),Qt::IgnoreAction);
122 data_device_manager->m_drag_can_drop = false;
123 data_device_manager->m_drag_data_offer = 0;
124 data_device_manager->m_drag_last_event_time = 0;
125 data_device_manager->m_drag_current_event_window = 0;
126 data_device_manager->m_drag_position = QPoint();
129 void QWaylandDataDeviceManager::motion(void *data,
130 struct wl_data_device *wl_data_device,
135 Q_UNUSED(wl_data_device);
136 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
137 if (time < data_device_manager->m_drag_last_event_time)
139 data_device_manager->m_drag_position = QPoint(wl_fixed_to_int(x), wl_fixed_to_int(y));
141 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
142 // QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),
143 // data_device_manager->m_drag_data_offer, data_device_manager->m_drag_position ,allActions);
144 // data_device_manager->m_drag_can_drop = response.accepted();
145 const char *offerMime = 0;
146 if (data_device_manager->m_drag_can_drop) {
147 offerMime = qPrintable(data_device_manager->m_drag_data_offer->formats_sys().at(0));
149 wl_data_offer_accept(data_device_manager->m_drag_data_offer->handle(),QWaylandDisplay::currentTimeMillisec(),offerMime);
152 void QWaylandDataDeviceManager::drop(void *data,
153 struct wl_data_device *wl_data_device)
155 Q_UNUSED(wl_data_device);
156 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
157 QWindow *window = data_device_manager->m_drag_current_event_window->window();
158 QMimeData *mime = data_device_manager->m_drag_data_offer;
159 // QPoint point = data_device_manager->m_drag_position;
160 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
164 // QWindowSystemInterface::handleDrop(window,mime,point,allActions);
168 void QWaylandDataDeviceManager::selection(void *data,
169 struct wl_data_device *wl_data_device,
170 struct wl_data_offer *id)
172 Q_UNUSED(wl_data_device);
173 QWaylandDataDeviceManager *handler = static_cast<QWaylandDataDeviceManager *>(data);
174 QWaylandDataOffer *mime = handler->m_selection_data_offer;
176 QWaylandDataSource *transfer_source = handler->m_selection_data_source;
177 delete transfer_source;
178 handler->m_selection_data_source = 0;
180 mime = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
181 handler->m_selection_data_offer = mime;
183 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
186 const struct wl_data_device_listener QWaylandDataDeviceManager::transfer_device_listener = {
187 QWaylandDataDeviceManager::data_offer,
188 QWaylandDataDeviceManager::enter,
189 QWaylandDataDeviceManager::leave,
190 QWaylandDataDeviceManager::motion,
191 QWaylandDataDeviceManager::drop,
192 QWaylandDataDeviceManager::selection
195 QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
197 , m_selection_data_offer(0)
198 , m_selection_data_source(0)
199 , m_drag_data_offer(0)
200 , m_drag_data_source(0)
202 , m_drag_icon_surface(0)
203 , m_drag_icon_buffer(0)
204 , m_drag_can_drop(false)
206 m_data_device_manager = static_cast<struct wl_data_device_manager *>(wl_display_bind(display->wl_display(),id,&wl_data_device_manager_interface));
208 // Create transfer devices for all input devices.
209 // ### This only works if we get the global before all devices and is surely wrong when hotplugging.
210 QList<QWaylandInputDevice *> inputDevices = m_display->inputDevices();
211 for (int i = 0; i < inputDevices.size();i++) {
212 inputDevices.at(i)->setTransferDevice(getDataDevice(inputDevices.at(i)));
216 QWaylandDataDeviceManager::~QWaylandDataDeviceManager()
218 wl_data_device_manager_destroy(m_data_device_manager);
221 struct wl_data_device *QWaylandDataDeviceManager::getDataDevice(QWaylandInputDevice *inputDevice)
223 struct wl_data_device *transfer_device = wl_data_device_manager_get_data_device(m_data_device_manager,
224 inputDevice->wl_seat());
225 wl_data_device_add_listener(transfer_device,&transfer_device_listener,this);
227 return transfer_device;
230 QWaylandDataOffer *QWaylandDataDeviceManager::selectionTransfer() const
232 return m_selection_data_offer;
235 void QWaylandDataDeviceManager::createAndSetDrag(QDrag *drag)
237 QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
241 if (m_drag_data_source) {
242 qDebug() << "QWaylandDndSelectionHandler::createAndSetDrag: Allready have a valid drag";
243 delete m_drag_data_source;
246 delete m_drag_data_offer;
247 m_drag_data_offer = 0;
249 m_drag_data_source = new QWaylandDataSource(this,drag->mimeData());
251 struct wl_data_device *transfer_device = inputDevice->transferDevice();
252 m_drag_surface = m_display->createSurface(this);
253 QPixmap pixmap = drag->pixmap();
254 if (pixmap.isNull()) {
255 // pixmap = QPlatformDrag::defaultPixmap();
258 m_drag_icon_buffer = new QWaylandShmBuffer(m_display, pixmap.size(), QImage::Format_ARGB32_Premultiplied);
261 QPainter p(m_drag_icon_buffer->image());
262 p.drawPixmap(0,0,pixmap);
265 m_drag_icon_surface = wl_compositor_create_surface(m_display->wl_compositor());
266 wl_surface_attach(m_drag_icon_surface, m_drag_icon_buffer->buffer(), -drag->hotSpot().x(), -drag->hotSpot().y());
268 wl_data_device_start_drag(transfer_device, m_drag_data_source->handle(), m_drag_surface, m_drag_icon_surface, QWaylandDisplay::currentTimeMillisec());
271 QMimeData *QWaylandDataDeviceManager::dragMime() const
273 if (m_drag_data_offer) {
274 return m_drag_data_offer;
275 } else if (m_drag_data_source){
276 return m_drag_data_source->mimeData();
281 bool QWaylandDataDeviceManager::canDropDrag() const
283 return m_drag_can_drop;
286 void QWaylandDataDeviceManager::cancelDrag()
288 wl_data_source_destroy(m_drag_data_source->handle() );
289 wl_surface_destroy(m_drag_icon_surface);
290 m_drag_data_source = 0;
293 void QWaylandDataDeviceManager::createAndSetSelectionSource(QMimeData *mimeData, QClipboard::Mode mode)
296 QWaylandDataSource *transfer_source = m_selection_data_source;
297 delete transfer_source;
299 transfer_source = new QWaylandDataSource(this,mimeData);
300 m_selection_data_source = transfer_source;
301 QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
303 inputDevice = m_display->inputDevices().first(); // try to survive in apps without any surfaces
304 struct wl_data_device *transfer_device = inputDevice->transferDevice();
305 wl_data_device_set_selection(transfer_device,transfer_source->handle(),QWaylandDisplay::currentTimeMillisec());
307 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
310 QWaylandDataSource *QWaylandDataDeviceManager::selectionTransferSource()
312 return m_selection_data_source;
316 QWaylandDisplay * QWaylandDataDeviceManager::display() const
321 struct wl_data_device_manager *QWaylandDataDeviceManager::handle() const
323 return m_data_device_manager;