1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QXCBDRAG_H
5#define QXCBDRAG_H
6
7#include <qpa/qplatformdrag.h>
8#include <private/qsimpledrag_p.h>
9#include <xcb/xcb.h>
10#include <qbackingstore.h>
11#include <qdatetime.h>
12#include <qlist.h>
13#include <qpixmap.h>
14#include <qpoint.h>
15#include <qpointer.h>
16#include <qrect.h>
17#include <qxcbobject.h>
18
19#include <QtCore/QDebug>
20
21QT_REQUIRE_CONFIG(draganddrop);
22
23QT_BEGIN_NAMESPACE
24
25class QWindow;
26class QPlatformWindow;
27class QXcbConnection;
28class QXcbWindow;
29class QXcbDropData;
30class QXcbScreen;
31class QDrag;
32class QShapedPixmapWindow;
33
34class QXcbDrag : public QXcbObject, public QBasicDrag, public QXcbWindowEventListener
35{
36public:
37 QXcbDrag(QXcbConnection *c);
38 ~QXcbDrag();
39
40 bool eventFilter(QObject *o, QEvent *e) override;
41
42 void startDrag() override;
43 void cancel() override;
44 void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
45 void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
46 void endDrag() override;
47
48 Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const override;
49
50 void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
51
52 void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0);
53 void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event);
54 void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event);
55 void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
56 Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { });
57
58 void handleStatus(const xcb_client_message_event_t *event);
59 void handleSelectionRequest(const xcb_selection_request_event_t *event);
60 void handleFinished(const xcb_client_message_event_t *event);
61
62 bool dndEnable(QXcbWindow *win, bool on);
63 bool ownsDragObject() const override;
64
65 void updatePixmap();
66 xcb_timestamp_t targetTime() { return target_time; }
67
68protected:
69 void timerEvent(QTimerEvent* e) override;
70
71 bool findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out);
72
73private:
74 friend class QXcbDropData;
75
76 void init();
77
78 void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event,
79 Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { });
80 void handle_xdnd_status(const xcb_client_message_event_t *event);
81 void send_leave();
82
83 Qt::DropAction toDropAction(xcb_atom_t atom) const;
84 Qt::DropActions toDropActions(const QList<xcb_atom_t> &atoms) const;
85 xcb_atom_t toXdndAction(Qt::DropAction a) const;
86
87 void readActionList();
88 void setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions);
89 void startListeningForActionListChanges();
90 void stopListeningForActionListChanges();
91
92 QPointer<QWindow> initiatorWindow;
93 QPointer<QWindow> currentWindow;
94 QPoint currentPosition;
95
96 QXcbDropData *m_dropData;
97 Qt::DropAction accepted_drop_action;
98
99 QWindow *desktop_proxy;
100
101 xcb_atom_t xdnd_dragsource;
102
103 // the types in this drop. 100 is no good, but at least it's big.
104 enum { xdnd_max_type = 100 };
105 QList<xcb_atom_t> xdnd_types;
106
107 // timestamp from XdndPosition and XdndDroptime for retrieving the data
108 xcb_timestamp_t target_time;
109 xcb_timestamp_t source_time;
110
111 // rectangle in which the answer will be the same
112 QRect source_sameanswer;
113 bool waiting_for_status;
114
115 // helpers for setting executed drop action outside application
116 bool dropped;
117 bool canceled;
118
119 // A window from Unity DnD Manager, which does not respect the XDnD spec
120 xcb_window_t xdndCollectionWindow = XCB_NONE;
121
122 // top-level window we sent position to last.
123 xcb_window_t current_target;
124 // window to send events to (always valid if current_target)
125 xcb_window_t current_proxy_target;
126
127 QXcbVirtualDesktop *current_virtual_desktop;
128
129 // 10 minute timer used to discard old XdndDrop transactions
130 static constexpr std::chrono::minutes XdndDropTransactionTimeout{10};
131 int cleanup_timer;
132
133 QList<xcb_atom_t> drag_types;
134
135 QList<xcb_atom_t> current_actions;
136 QList<xcb_atom_t> drop_actions;
137
138 struct Transaction
139 {
140 xcb_timestamp_t timestamp;
141 xcb_window_t target;
142 xcb_window_t proxy_target;
143 QPlatformWindow *targetWindow;
144// QWidget *embedding_widget;
145 QPointer<QDrag> drag;
146 QTime time;
147 };
148 friend class QTypeInfo<Transaction>;
149 QList<Transaction> transactions;
150
151 int transaction_expiry_timer;
152 void restartDropExpiryTimer();
153 int findTransactionByWindow(xcb_window_t window);
154 int findTransactionByTime(xcb_timestamp_t timestamp);
155 xcb_window_t findRealWindow(const QPoint & pos, xcb_window_t w, int md, bool ignoreNonXdndAwareWindows);
156};
157Q_DECLARE_TYPEINFO(QXcbDrag::Transaction, Q_RELOCATABLE_TYPE);
158
159QT_END_NAMESPACE
160
161#endif
162

source code of qtbase/src/plugins/platforms/xcb/qxcbdrag.h