81972e83ebc5ada73722b5969cfb5b70fa489c48
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylanddatadevicemanager.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylanddatadevicemanager.h"
43
44 #include "qwaylandinputdevice.h"
45 #include "qwaylanddataoffer.h"
46 #include "qwaylanddatasource.h"
47 #include "qwaylandshmbackingstore.h"
48
49 #include <wayland-client-protocol.h>
50 #include <wayland-client.h>
51
52 #include <QtGui/QGuiApplication>
53 #include <QtGui/private/qguiapplication_p.h>
54 #include <qpa/qplatformclipboard.h>
55 #include <QtGui/QPainter>
56
57 #include <QWindowSystemInterface>
58
59 #include <QtCore/QDebug>
60
61 void QWaylandDataDeviceManager::data_offer(void *data,
62                    struct wl_data_device *data_device,
63                    uint32_t id)
64 {
65
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);
73
74
75     new QWaylandDataOffer(handler->display(),data_offer);
76 }
77
78 void QWaylandDataDeviceManager::enter(void *data,
79               struct wl_data_device *wl_data_device,
80               uint32_t time,
81               struct wl_surface *surface,
82               wl_fixed_t x,
83               wl_fixed_t y,
84               struct wl_data_offer *id)
85 {
86
87     Q_UNUSED(wl_data_device);
88     Q_UNUSED(x);
89     Q_UNUSED(y);
90     QWaylandDataDeviceManager *data_device_manager = static_cast<QWaylandDataDeviceManager *>(data);
91     if (time < data_device_manager->m_drag_last_event_time)
92         return;
93     data_device_manager->m_drag_last_event_time = time;
94
95     data_device_manager->m_drag_current_event_window = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface));
96     if (!surface)
97         return;
98     QWaylandDataOffer *offer = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
99     if (!offer)
100         return;
101
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);
111     } else {
112         wl_data_offer_accept(offer->handle(),QWaylandDisplay::currentTimeMillisec(),0);
113     }
114 }
115
116 void QWaylandDataDeviceManager::leave(void *data,
117               struct wl_data_device *wl_data_device)
118 {
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();
127 }
128
129 void QWaylandDataDeviceManager::motion(void *data,
130                struct wl_data_device *wl_data_device,
131                uint32_t time,
132                wl_fixed_t x,
133                wl_fixed_t y)
134 {
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)
138         return;
139     data_device_manager->m_drag_position = QPoint(wl_fixed_to_int(x), wl_fixed_to_int(y));
140
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));
148     }
149     wl_data_offer_accept(data_device_manager->m_drag_data_offer->handle(),QWaylandDisplay::currentTimeMillisec(),offerMime);
150 }
151
152 void QWaylandDataDeviceManager::drop(void *data,
153              struct wl_data_device *wl_data_device)
154 {
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;
161
162     Q_UNUSED(window);
163     Q_UNUSED(mime);
164 //    QWindowSystemInterface::handleDrop(window,mime,point,allActions);
165 }
166
167
168 void QWaylandDataDeviceManager::selection(void *data,
169                                             struct wl_data_device *wl_data_device,
170                                             struct wl_data_offer *id)
171 {
172     Q_UNUSED(wl_data_device);
173     QWaylandDataDeviceManager *handler = static_cast<QWaylandDataDeviceManager *>(data);
174     QWaylandDataOffer *mime = handler->m_selection_data_offer;
175     delete mime;
176     QWaylandDataSource *transfer_source = handler->m_selection_data_source;
177     delete transfer_source;
178     handler->m_selection_data_source = 0;
179
180     mime = static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id));
181     handler->m_selection_data_offer = mime;
182
183     QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
184 }
185
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
193 };
194
195 QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
196     : m_display(display)
197     , m_selection_data_offer(0)
198     , m_selection_data_source(0)
199     , m_drag_data_offer(0)
200     , m_drag_data_source(0)
201     , m_drag_surface(0)
202     , m_drag_icon_surface(0)
203     , m_drag_icon_buffer(0)
204     , m_drag_can_drop(false)
205 {
206     m_data_device_manager = static_cast<struct wl_data_device_manager *>(wl_display_bind(display->wl_display(),id,&wl_data_device_manager_interface));
207
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)));
213     }
214 }
215
216 QWaylandDataDeviceManager::~QWaylandDataDeviceManager()
217 {
218     wl_data_device_manager_destroy(m_data_device_manager);
219 }
220
221 struct wl_data_device *QWaylandDataDeviceManager::getDataDevice(QWaylandInputDevice *inputDevice)
222 {
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);
226
227     return transfer_device;
228 }
229
230 QWaylandDataOffer *QWaylandDataDeviceManager::selectionTransfer() const
231 {
232     return m_selection_data_offer;
233 }
234
235 void QWaylandDataDeviceManager::createAndSetDrag(QDrag *drag)
236 {
237     QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
238     if (!inputDevice)
239         return;
240
241     if (m_drag_data_source) {
242         qDebug() << "QWaylandDndSelectionHandler::createAndSetDrag: Allready have a valid drag";
243         delete m_drag_data_source;
244     }
245
246     delete m_drag_data_offer;
247     m_drag_data_offer = 0;
248
249     m_drag_data_source = new QWaylandDataSource(this,drag->mimeData());
250
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();
256     }
257
258     m_drag_icon_buffer = new QWaylandShmBuffer(m_display, pixmap.size(), QImage::Format_ARGB32_Premultiplied);
259
260     {
261         QPainter p(m_drag_icon_buffer->image());
262         p.drawPixmap(0,0,pixmap);
263     }
264
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());
267
268     wl_data_device_start_drag(transfer_device, m_drag_data_source->handle(), m_drag_surface, m_drag_icon_surface, QWaylandDisplay::currentTimeMillisec());
269 }
270
271 QMimeData *QWaylandDataDeviceManager::dragMime() const
272 {
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();
277     }
278     return 0;
279 }
280
281 bool QWaylandDataDeviceManager::canDropDrag() const
282 {
283     return m_drag_can_drop;
284 }
285
286 void QWaylandDataDeviceManager::cancelDrag()
287 {
288     wl_data_source_destroy(m_drag_data_source->handle() );
289     wl_surface_destroy(m_drag_icon_surface);
290     m_drag_data_source = 0;
291 }
292
293 void QWaylandDataDeviceManager::createAndSetSelectionSource(QMimeData *mimeData, QClipboard::Mode mode)
294 {
295     Q_UNUSED(mode);
296     QWaylandDataSource *transfer_source = m_selection_data_source;
297     delete transfer_source;
298
299     transfer_source = new QWaylandDataSource(this,mimeData);
300     m_selection_data_source = transfer_source;
301     QWaylandInputDevice *inputDevice = m_display->lastKeyboardFocusInputDevice();
302     if (!inputDevice)
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());
306
307     QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard);
308 }
309
310 QWaylandDataSource *QWaylandDataDeviceManager::selectionTransferSource()
311 {
312     return m_selection_data_source;
313 }
314
315
316 QWaylandDisplay * QWaylandDataDeviceManager::display() const
317 {
318     return m_display;
319 }
320
321 struct wl_data_device_manager *QWaylandDataDeviceManager::handle() const
322 {
323     return m_data_device_manager;
324 }
325
326