1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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,
63 struct wl_data_offer *id)
65 QWaylandDataDeviceManager *handler = static_cast<QWaylandDataDeviceManager *>(data);
67 new QWaylandDataOffer(handler->display(),id);
70 void QWaylandDataDeviceManager::enter(void *data,
71 struct wl_data_device *wl_data_device,
73 struct wl_surface *surface,
76 struct wl_data_offer *id)
79 Q_UNUSED(wl_data_device);
82 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
83 if (time < data_device_manager->m_drag_last_event_time)
85 data_device_manager->m_drag_last_event_time = time;
87 data_device_manager->m_drag_current_event_window = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface));
90 QWaylandDataOffer *offer = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
95 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
96 // QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),
97 // offer,point,allActions);
98 // data_device_manager->m_drag_can_drop = response.accepted();
99 data_device_manager->m_drag_data_offer = offer;
100 if (data_device_manager->m_drag_can_drop) {
101 const char *first_offer = qPrintable(offer->formats_sys().at(0));
102 wl_data_offer_accept(offer->handle(),QWaylandDisplay::currentTimeMillisec(),first_offer);
104 wl_data_offer_accept(offer->handle(),QWaylandDisplay::currentTimeMillisec(),0);
108 void QWaylandDataDeviceManager::leave(void *data,
109 struct wl_data_device *wl_data_device)
111 Q_UNUSED(wl_data_device);
112 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
113 // QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),0,QPoint(0,0),Qt::IgnoreAction);
114 data_device_manager->m_drag_can_drop = false;
115 data_device_manager->m_drag_data_offer = 0;
116 data_device_manager->m_drag_last_event_time = 0;
117 data_device_manager->m_drag_current_event_window = 0;
118 data_device_manager->m_drag_position = QPoint();
121 void QWaylandDataDeviceManager::motion(void *data,
122 struct wl_data_device *wl_data_device,
127 Q_UNUSED(wl_data_device);
128 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
129 if (time < data_device_manager->m_drag_last_event_time)
131 data_device_manager->m_drag_position = QPoint(wl_fixed_to_int(x), wl_fixed_to_int(y));
133 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
134 // QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(data_device_manager->m_drag_current_event_window->window(),
135 // data_device_manager->m_drag_data_offer, data_device_manager->m_drag_position ,allActions);
136 // data_device_manager->m_drag_can_drop = response.accepted();
137 const char *offerMime = 0;
138 if (data_device_manager->m_drag_can_drop) {
139 offerMime = qPrintable(data_device_manager->m_drag_data_offer->formats_sys().at(0));
141 wl_data_offer_accept(data_device_manager->m_drag_data_offer->handle(),QWaylandDisplay::currentTimeMillisec(),offerMime);
144 void QWaylandDataDeviceManager::drop(void *data,
145 struct wl_data_device *wl_data_device)
147 Q_UNUSED(wl_data_device);
148 QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
149 QWindow *window = data_device_manager->m_drag_current_event_window->window();
150 QMimeData *mime = data_device_manager->m_drag_data_offer;
151 // QPoint point = data_device_manager->m_drag_position;
152 // Qt::DropActions allActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
156 // QWindowSystemInterface::handleDrop(window,mime,point,allActions);
160 void QWaylandDataDeviceManager::selection(void *data,
161 struct wl_data_device *wl_data_device,
162 struct wl_data_offer *id)
164 Q_UNUSED(wl_data_device);
166 QWaylandDataDeviceManager *handler = static_cast<QWaylandDataDeviceManager *>(data);
167 QWaylandDataOffer *mime = handler->m_selection_data_offer;
169 QWaylandDataSource *transfer_source = handler->m_selection_data_source;
170 delete transfer_source;
171 handler->m_selection_data_source = 0;
174 mime = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
175 handler->m_selection_data_offer = mime;
177 handler->m_selection_data_offer = 0;
180 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
183 const struct wl_data_device_listener QWaylandDataDeviceManager::transfer_device_listener = {
184 QWaylandDataDeviceManager::data_offer,
185 QWaylandDataDeviceManager::enter,
186 QWaylandDataDeviceManager::leave,
187 QWaylandDataDeviceManager::motion,
188 QWaylandDataDeviceManager::drop,
189 QWaylandDataDeviceManager::selection
192 QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
194 , m_selection_data_offer(0)
195 , m_selection_data_source(0)
196 , m_drag_data_offer(0)
197 , m_drag_data_source(0)
199 , m_drag_icon_surface(0)
200 , m_drag_icon_buffer(0)
201 , m_drag_can_drop(false)
203 m_data_device_manager = static_cast<struct wl_data_device_manager *>(wl_display_bind(display->wl_display(),id,&wl_data_device_manager_interface));
205 // Create transfer devices for all input devices.
206 // ### This only works if we get the global before all devices and is surely wrong when hotplugging.
207 QList<QWaylandInputDevice *> inputDevices = m_display->inputDevices();
208 for (int i = 0; i < inputDevices.size();i++) {
209 inputDevices.at(i)->setTransferDevice(getDataDevice(inputDevices.at(i)));
213 QWaylandDataDeviceManager::~QWaylandDataDeviceManager()
215 wl_data_device_manager_destroy(m_data_device_manager);
218 struct wl_data_device *QWaylandDataDeviceManager::getDataDevice(QWaylandInputDevice *inputDevice)
220 struct wl_data_device *transfer_device = wl_data_device_manager_get_data_device(m_data_device_manager,
221 inputDevice->wl_seat());
222 wl_data_device_add_listener(transfer_device,&transfer_device_listener,this);
224 return transfer_device;
227 QWaylandDataOffer *QWaylandDataDeviceManager::selectionTransfer() const
229 return m_selection_data_offer;
232 void QWaylandDataDeviceManager::createAndSetDrag(QDrag *drag)
234 QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
238 if (m_drag_data_source) {
239 qDebug() << "QWaylandDndSelectionHandler::createAndSetDrag: Allready have a valid drag";
240 delete m_drag_data_source;
243 delete m_drag_data_offer;
244 m_drag_data_offer = 0;
246 m_drag_data_source = new QWaylandDataSource(this,drag->mimeData());
248 struct wl_data_device *transfer_device = inputDevice->transferDevice();
249 m_drag_surface = m_display->createSurface(this);
250 QPixmap pixmap = drag->pixmap();
251 if (pixmap.isNull()) {
252 // pixmap = QPlatformDrag::defaultPixmap();
255 m_drag_icon_buffer = new QWaylandShmBuffer(m_display, pixmap.size(), QImage::Format_ARGB32_Premultiplied);
258 QPainter p(m_drag_icon_buffer->image());
259 p.drawPixmap(0,0,pixmap);
262 m_drag_icon_surface = wl_compositor_create_surface(m_display->wl_compositor());
263 wl_surface_attach(m_drag_icon_surface, m_drag_icon_buffer->buffer(), -drag->hotSpot().x(), -drag->hotSpot().y());
265 wl_data_device_start_drag(transfer_device, m_drag_data_source->handle(), m_drag_surface, m_drag_icon_surface, QWaylandDisplay::currentTimeMillisec());
268 QMimeData *QWaylandDataDeviceManager::dragMime() const
270 if (m_drag_data_offer) {
271 return m_drag_data_offer;
272 } else if (m_drag_data_source){
273 return m_drag_data_source->mimeData();
278 bool QWaylandDataDeviceManager::canDropDrag() const
280 return m_drag_can_drop;
283 void QWaylandDataDeviceManager::cancelDrag()
285 wl_data_source_destroy(m_drag_data_source->handle() );
286 wl_surface_destroy(m_drag_icon_surface);
287 m_drag_data_source = 0;
290 void QWaylandDataDeviceManager::createAndSetSelectionSource(QMimeData *mimeData, QClipboard::Mode mode)
293 QWaylandDataSource *transfer_source = m_selection_data_source;
294 delete transfer_source;
296 transfer_source = new QWaylandDataSource(this,mimeData);
297 m_selection_data_source = transfer_source;
298 QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
300 inputDevice = m_display->inputDevices().first(); // try to survive in apps without any surfaces
301 struct wl_data_device *transfer_device = inputDevice->transferDevice();
302 wl_data_device_set_selection(transfer_device,transfer_source->handle(),QWaylandDisplay::currentTimeMillisec());
304 QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
307 QWaylandDataSource *QWaylandDataDeviceManager::selectionTransferSource()
309 return m_selection_data_source;
313 QWaylandDisplay * QWaylandDataDeviceManager::display() const
318 struct wl_data_device_manager *QWaylandDataDeviceManager::handle() const
320 return m_data_device_manager;