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