// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QXCBDRAG_H #define QXCBDRAG_H #include #include #include #include #include #include #include #include #include #include #include #include #include QT_REQUIRE_CONFIG(draganddrop); QT_BEGIN_NAMESPACE class QWindow; class QPlatformWindow; class QXcbConnection; class QXcbWindow; class QXcbDropData; class QXcbScreen; class QDrag; class QShapedPixmapWindow; class QXcbDrag : public QXcbObject, public QBasicDrag, public QXcbWindowEventListener { public: QXcbDrag(QXcbConnection *c); ~QXcbDrag(); bool eventFilter(QObject *o, QEvent *e) override; void startDrag() override; void cancel() override; void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override; void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override; void endDrag() override; Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const override; void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override; void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0); void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event, Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { }); void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); void handleFinished(const xcb_client_message_event_t *event); bool dndEnable(QXcbWindow *win, bool on); bool ownsDragObject() const override; void updatePixmap(); xcb_timestamp_t targetTime() { return target_time; } protected: void timerEvent(QTimerEvent* e) override; bool findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out); private: friend class QXcbDropData; void init(); void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event, Qt::MouseButtons b = { }, Qt::KeyboardModifiers mods = { }); void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); Qt::DropAction toDropAction(xcb_atom_t atom) const; Qt::DropActions toDropActions(const QList &atoms) const; xcb_atom_t toXdndAction(Qt::DropAction a) const; void readActionList(); void setActionList(Qt::DropAction requestedAction, Qt::DropActions supportedActions); void startListeningForActionListChanges(); void stopListeningForActionListChanges(); QPointer initiatorWindow; QPointer currentWindow; QPoint currentPosition; QXcbDropData *m_dropData; Qt::DropAction accepted_drop_action; QWindow *desktop_proxy; xcb_atom_t xdnd_dragsource; // the types in this drop. 100 is no good, but at least it's big. enum { xdnd_max_type = 100 }; QList xdnd_types; // timestamp from XdndPosition and XdndDroptime for retrieving the data xcb_timestamp_t target_time; xcb_timestamp_t source_time; // rectangle in which the answer will be the same QRect source_sameanswer; bool waiting_for_status; // helpers for setting executed drop action outside application bool dropped; bool canceled; // A window from Unity DnD Manager, which does not respect the XDnD spec xcb_window_t xdndCollectionWindow = XCB_NONE; // top-level window we sent position to last. xcb_window_t current_target; // window to send events to (always valid if current_target) xcb_window_t current_proxy_target; QXcbVirtualDesktop *current_virtual_desktop; // 10 minute timer used to discard old XdndDrop transactions enum { XdndDropTransactionTimeout = 600000 }; int cleanup_timer; QList drag_types; QList current_actions; QList drop_actions; struct Transaction { xcb_timestamp_t timestamp; xcb_window_t target; xcb_window_t proxy_target; QPlatformWindow *targetWindow; // QWidget *embedding_widget; QPointer drag; QTime time; }; friend class QTypeInfo; QList transactions; int transaction_expiry_timer; void restartDropExpiryTimer(); int findTransactionByWindow(xcb_window_t window); int findTransactionByTime(xcb_timestamp_t timestamp); xcb_window_t findRealWindow(const QPoint & pos, xcb_window_t w, int md, bool ignoreNonXdndAwareWindows); }; Q_DECLARE_TYPEINFO(QXcbDrag::Transaction, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif