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

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