1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QXCBDRAG_H
41 #define QXCBDRAG_H
42 
43 #include <qpa/qplatformdrag.h>
44 #include <private/qsimpledrag_p.h>
45 #include <qxcbobject.h>
46 #include <xcb/xcb.h>
47 #include <qpoint.h>
48 #include <qrect.h>
49 #include <qsharedpointer.h>
50 #include <qpointer.h>
51 #include <qvector.h>
52 #include <qdatetime.h>
53 #include <qpixmap.h>
54 #include <qbackingstore.h>
55 
56 #include <QtCore/QDebug>
57 
58 QT_REQUIRE_CONFIG(draganddrop);
59 
60 QT_BEGIN_NAMESPACE
61 
62 class QWindow;
63 class QPlatformWindow;
64 class QXcbConnection;
65 class QXcbWindow;
66 class QXcbDropData;
67 class QXcbScreen;
68 class QDrag;
69 class QShapedPixmapWindow;
70 
71 class QXcbDrag : public QXcbObject, public QBasicDrag, public QXcbWindowEventListener
72 {
73 public:
74     QXcbDrag(QXcbConnection *c);
75     ~QXcbDrag();
76 
77     bool eventFilter(QObject *o, QEvent *e) override;
78 
79     void startDrag() override;
80     void cancel() override;
81     void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
82     void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
83     void endDrag() override;
84 
85     Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const override;
86 
87     void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
88 
89     void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0);
90     void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event);
91     void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event);
92     void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
93                     Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { });
94 
95     void handleStatus(const xcb_client_message_event_t *event);
96     void handleSelectionRequest(const xcb_selection_request_event_t *event);
97     void handleFinished(const xcb_client_message_event_t *event);
98 
99     bool dndEnable(QXcbWindow *win, bool on);
100     bool ownsDragObject() const override;
101 
102     void updatePixmap();
targetTime()103     xcb_timestamp_t targetTime() { return target_time; }
104 
105 protected:
106     void timerEvent(QTimerEvent* e) override;
107 
108     bool findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out);
109 
110 private:
111     friend class QXcbDropData;
112 
113     void init();
114 
115     void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event,
116                               Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { });
117     void handle_xdnd_status(const xcb_client_message_event_t *event);
118     void send_leave();
119 
120     Qt::DropAction toDropAction(xcb_atom_t atom) const;
121     Qt::DropActions toDropActions(const QVector<xcb_atom_t> &atoms) const;
122     xcb_atom_t toXdndAction(Qt::DropAction a) const;
123 
124     void readActionList();
125     void setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions);
126     void startListeningForActionListChanges();
127     void stopListeningForActionListChanges();
128 
129     QPointer<QWindow> initiatorWindow;
130     QPointer<QWindow> currentWindow;
131     QPoint currentPosition;
132 
133     QXcbDropData *m_dropData;
134     Qt::DropAction accepted_drop_action;
135 
136     QWindow *desktop_proxy;
137 
138     xcb_atom_t xdnd_dragsource;
139 
140     // the types in this drop. 100 is no good, but at least it's big.
141     enum { xdnd_max_type = 100 };
142     QVector<xcb_atom_t> xdnd_types;
143 
144     // timestamp from XdndPosition and XdndDroptime for retrieving the data
145     xcb_timestamp_t target_time;
146     xcb_timestamp_t source_time;
147 
148     // rectangle in which the answer will be the same
149     QRect source_sameanswer;
150     bool waiting_for_status;
151 
152     // helpers for setting executed drop action outside application
153     bool dropped;
154     bool canceled;
155 
156     // A window from Unity DnD Manager, which does not respect the XDnD spec
157     xcb_window_t xdndCollectionWindow = XCB_NONE;
158 
159     // top-level window we sent position to last.
160     xcb_window_t current_target;
161     // window to send events to (always valid if current_target)
162     xcb_window_t current_proxy_target;
163 
164     QXcbVirtualDesktop *current_virtual_desktop;
165 
166     // 10 minute timer used to discard old XdndDrop transactions
167     enum { XdndDropTransactionTimeout = 600000 };
168     int cleanup_timer;
169 
170     QVector<xcb_atom_t> drag_types;
171 
172     QVector<xcb_atom_t> current_actions;
173     QVector<xcb_atom_t> drop_actions;
174 
175     struct Transaction
176     {
177         xcb_timestamp_t timestamp;
178         xcb_window_t target;
179         xcb_window_t proxy_target;
180         QPlatformWindow *targetWindow;
181 //        QWidget *embedding_widget;
182         QPointer<QDrag> drag;
183         QTime time;
184     };
185     friend class QTypeInfo<Transaction>;
186     QVector<Transaction> transactions;
187 
188     int transaction_expiry_timer;
189     void restartDropExpiryTimer();
190     int findTransactionByWindow(xcb_window_t window);
191     int findTransactionByTime(xcb_timestamp_t timestamp);
192     xcb_window_t findRealWindow(const QPoint & pos, xcb_window_t w, int md, bool ignoreNonXdndAwareWindows);
193 };
194 Q_DECLARE_TYPEINFO(QXcbDrag::Transaction, Q_MOVABLE_TYPE);
195 
196 QT_END_NAMESPACE
197 
198 #endif
199