1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsCorePrerequisites.h" |
6 | #include <X11/X.h> |
7 | #include <X11/Xlib.h> |
8 | |
9 | namespace bs |
10 | { |
11 | /** Handles X11 drag and drop functionality. */ |
12 | class LinuxDragAndDrop |
13 | { |
14 | /** Possible states of the DND manager. */ |
15 | enum class State |
16 | { |
17 | Inactive, |
18 | Entered, |
19 | Active |
20 | }; |
21 | |
22 | /** Type of drag and drop operation. */ |
23 | enum class DragAndDropOpType |
24 | { |
25 | Enter, |
26 | DragOver, |
27 | Drop, |
28 | Leave |
29 | }; |
30 | |
31 | /** Structure describing a drag and drop operation. */ |
32 | struct DragAndDropOp |
33 | { |
34 | DragAndDropOp(DragAndDropOpType type, DropTarget* target) |
35 | :type(type), target(target) |
36 | { } |
37 | |
38 | DragAndDropOp(DragAndDropOpType type, DropTarget* target, const Vector2I& pos) |
39 | :type(type), target(target), position(pos) |
40 | { } |
41 | |
42 | DragAndDropOp(DragAndDropOpType type, DropTarget* target, const Vector2I& pos, |
43 | const Vector<Path>& fileList) |
44 | :type(type), target(target), position(pos), fileList(fileList) |
45 | { } |
46 | |
47 | DragAndDropOpType type; |
48 | DropTarget* target; |
49 | Vector2I position; |
50 | Vector<Path> fileList; |
51 | }; |
52 | |
53 | /** Represents a single registered drop area. */ |
54 | struct DropArea |
55 | { |
56 | DropArea(DropTarget* target, const Rect2I& area) |
57 | :target(target), area(area) |
58 | { } |
59 | |
60 | DropTarget* target; |
61 | Rect2I area; |
62 | }; |
63 | |
64 | /** Type of operations that can happen to a DropArea. */ |
65 | enum class DropAreaOpType |
66 | { |
67 | Register, /**< New DropArea is being registered. */ |
68 | Unregister, /**< DropArea is being unregistered. */ |
69 | Update /**< DropArea was updated. */ |
70 | }; |
71 | |
72 | /** Operation that in some way modifies a DropArea. */ |
73 | struct DropAreaOp |
74 | { |
75 | DropAreaOp(DropTarget* target, DropAreaOpType type, const Rect2I& area = Rect2I::EMPTY) |
76 | :target(target), area(area), type(type) |
77 | { } |
78 | |
79 | DropTarget* target; |
80 | Rect2I area; |
81 | DropAreaOpType type; |
82 | }; |
83 | |
84 | public: |
85 | /** |
86 | * Initializes the drag and drop system. Must be called before any other drag and drop methods are called. |
87 | * |
88 | * @note Core thread only. |
89 | */ |
90 | static void startUp(::Display* xDisplay); |
91 | |
92 | /** |
93 | * Shuts down the drag and drop system. Should be called after no more calls to the system are expected. |
94 | * |
95 | * @note Core thread only. |
96 | */ |
97 | static void shutDown(); |
98 | |
99 | /** |
100 | * Triggers any drag and drop events. |
101 | * |
102 | * @note Sim thread only. |
103 | */ |
104 | static void update(); |
105 | |
106 | /** |
107 | * Marks an X11 window as drag and drop aware (being able to accept and send drag and drop events). |
108 | * |
109 | * @note Core thread only. |
110 | */ |
111 | static void makeDNDAware(::Window xWindow); |
112 | |
113 | /** |
114 | * Registers a new drop target Any further events processed will take this target into account, trigger its event |
115 | * and populate its data if a drop occurs. |
116 | * |
117 | * @note Thread safe. |
118 | */ |
119 | static void registerDropTarget(DropTarget* target); |
120 | |
121 | /** |
122 | * Updates information about previous registered DropTarget. Call this when drop target area changes. |
123 | * |
124 | * @note Thread safe. |
125 | */ |
126 | static void updateDropTarget(DropTarget* target); |
127 | |
128 | /** |
129 | * Unregisters a drop target. Its events will no longer be triggered. |
130 | * |
131 | * @note Thread safe. |
132 | */ |
133 | static void unregisterDropTarget(DropTarget* target); |
134 | |
135 | /** |
136 | * Processes X11 ClientMessage event and handles any messages relating to drag and drop. Returns true if a message |
137 | * was handled, or false if it needs to be handled by the caller. |
138 | * |
139 | * @note Core thread only. |
140 | */ |
141 | static bool handleClientMessage(XClientMessageEvent& event); |
142 | |
143 | /** |
144 | * Processes X11 SelectionNotify event and handles it if it relates to drag and drop. Returns true if the event was |
145 | * handled, or false otherwise. |
146 | * |
147 | * @note Core thread only. |
148 | */ |
149 | static bool handleSelectionNotify(XSelectionEvent& event); |
150 | |
151 | private: |
152 | static ::Display* sXDisplay; |
153 | static bool sDragActive; |
154 | static Vector<DropArea> sDropAreas; |
155 | static Mutex sMutex; |
156 | static INT32 sDNDVersion; |
157 | static Atom sDNDType; |
158 | static ::Window sDNDSource; |
159 | static Vector2I sDragPosition; |
160 | static Vector<DragAndDropOp> sQueuedOperations; |
161 | static Vector<DropAreaOp> sQueuedAreaOperations; |
162 | |
163 | // Awareness |
164 | static Atom sXdndAware; |
165 | |
166 | // Selection handling |
167 | static Atom sXdndSelection; |
168 | |
169 | // Client messages |
170 | static Atom sXdndEnter; |
171 | static Atom sXdndLeave; |
172 | static Atom sXdndPosition; |
173 | static Atom sXdndStatus; |
174 | static Atom sXdndDrop; |
175 | static Atom sXdndFinished; |
176 | |
177 | // Actions |
178 | static Atom sXdndActionCopy; |
179 | |
180 | // Type list |
181 | static Atom sXdndTypeList; |
182 | |
183 | // Other |
184 | static Atom sPRIMARY; |
185 | }; |
186 | } |
187 | |
188 | |