1 | /* $Id: wayland-helper.h 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * Guest Additions - Definitions for Wayland helpers.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 | #ifndef GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_h
|
---|
29 | #define GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_h
|
---|
30 | #ifndef RT_WITHOUT_PRAGMA_ONCE
|
---|
31 | # pragma once
|
---|
32 | #endif
|
---|
33 |
|
---|
34 | #include <iprt/asm.h>
|
---|
35 | #include <iprt/time.h>
|
---|
36 |
|
---|
37 | #include <VBox/VBoxGuestLib.h>
|
---|
38 | #include <VBox/GuestHost/clipboard-helper.h>
|
---|
39 |
|
---|
40 | #include "clipboard.h"
|
---|
41 |
|
---|
42 | /** Helper capabilities list. */
|
---|
43 |
|
---|
44 | /** Indicates that helper does not support any functionality (initializer). */
|
---|
45 | #define VBOX_WAYLAND_HELPER_CAP_NONE (0)
|
---|
46 | /** Indicates that helper supported shared clipboard functionality. */
|
---|
47 | #define VBOX_WAYLAND_HELPER_CAP_CLIPBOARD RT_BIT(1)
|
---|
48 | /** Indicates that helper supported drag-and-drop functionality. */
|
---|
49 | #define VBOX_WAYLAND_HELPER_CAP_DND RT_BIT(2)
|
---|
50 |
|
---|
51 | /** Default time interval to wait for value to arrive over IPC. */
|
---|
52 | #define VBCL_WAYLAND_VALUE_WAIT_TIMEOUT_MS (1000)
|
---|
53 | /** Default time interval to wait for clipboard content to arrive over IPC. */
|
---|
54 | #define VBCL_WAYLAND_DATA_WAIT_TIMEOUT_MS (2000)
|
---|
55 | /** Generic relax interval while polling value changes. */
|
---|
56 | #define VBCL_WAYLAND_RELAX_INTERVAL_MS (50)
|
---|
57 | /** Maximum number of participants who can join session. */
|
---|
58 | #define VBCL_WAYLAND_SESSION_USERS_MAX (10)
|
---|
59 | /** Value which determines if session structure was initialized. */
|
---|
60 | #define VBCL_WAYLAND_SESSION_MAGIC (0xDEADBEEF)
|
---|
61 |
|
---|
62 | /** Session states. */
|
---|
63 | typedef enum
|
---|
64 | {
|
---|
65 | /** Session is not active. */
|
---|
66 | VBCL_WL_SESSION_STATE_IDLE,
|
---|
67 | /** Session is being initialized. */
|
---|
68 | VBCL_WL_SESSION_STATE_STARTING,
|
---|
69 | /** Session has started and now can be joined. */
|
---|
70 | VBCL_WL_SESSION_STATE_STARTED,
|
---|
71 | /** Session is terminating. */
|
---|
72 | VBCL_WL_SESSION_STATE_TERMINATING
|
---|
73 | } vbcl_wl_session_state_t;
|
---|
74 |
|
---|
75 | /** Session type.
|
---|
76 | *
|
---|
77 | * Type determines the purpose of session. It is
|
---|
78 | * also serves a sanity check purpose when different
|
---|
79 | * participants join session with certain intention.
|
---|
80 | * Session type can only be set when session is
|
---|
81 | * in STARTING state and reset when session is TERMINATING.
|
---|
82 | */
|
---|
83 | typedef enum
|
---|
84 | {
|
---|
85 | /** Initializer. */
|
---|
86 | VBCL_WL_SESSION_TYPE_INVALID,
|
---|
87 | /** Copy clipboard data to the guest. */
|
---|
88 | VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_GUEST,
|
---|
89 | /** Announce clipboard formats to the host. */
|
---|
90 | VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST,
|
---|
91 | /** Copy clipboard data to the host. */
|
---|
92 | VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_HOST
|
---|
93 | } vbcl_wl_session_type_t;
|
---|
94 |
|
---|
95 | /** Session private data. */
|
---|
96 | typedef struct
|
---|
97 | {
|
---|
98 | /** Magic number which indicates if session
|
---|
99 | * was previously initialized. */
|
---|
100 | volatile uint32_t u32Magic;
|
---|
101 |
|
---|
102 | /** Session state, synchronization element. */
|
---|
103 | volatile vbcl_wl_session_state_t enmState;
|
---|
104 |
|
---|
105 | /** Session type. */
|
---|
106 | vbcl_wl_session_type_t enmType;
|
---|
107 |
|
---|
108 | /** Session description, used for logging purpose
|
---|
109 | * to distinguish between operations flow. */
|
---|
110 | const char *pcszDesc;
|
---|
111 |
|
---|
112 | /** Current number of session users. When session
|
---|
113 | * switches into TERMINATING state, it will wait
|
---|
114 | * number of participants to drop to 1 before releasing
|
---|
115 | * session resources and resetting internal data to
|
---|
116 | * default values. */
|
---|
117 | volatile uint32_t cUsers;
|
---|
118 | } vbcl_wl_session_t;
|
---|
119 |
|
---|
120 | /** Session state change callback.
|
---|
121 | *
|
---|
122 | * Data which belongs to a session must be accessed from
|
---|
123 | * session callback only. It ensures session data integrity
|
---|
124 | * and prevents access to data when session is not yet
|
---|
125 | * initialized or already terminated.
|
---|
126 | *
|
---|
127 | * @returns IPRT status code.
|
---|
128 | * @param enmSessionType Session type, provided for consistency
|
---|
129 | * check to make sure given callback is
|
---|
130 | * intended to be triggered in context of
|
---|
131 | * given session type.
|
---|
132 | * @param pvUser Optional user data.
|
---|
133 | */
|
---|
134 | typedef DECLCALLBACKTYPE(int, FNVBCLWLSESSIONCB, (vbcl_wl_session_type_t enmSessionType, void *pvUser));
|
---|
135 | /** Pointer to FNVBCLWLSESSIONCB. */
|
---|
136 | typedef FNVBCLWLSESSIONCB *PFNVBCLWLSESSIONCB;
|
---|
137 |
|
---|
138 | /**
|
---|
139 | * Wayland Desktop Environment helper definition structure.
|
---|
140 | */
|
---|
141 | typedef struct
|
---|
142 | {
|
---|
143 | /** A short helper name. 16 chars maximum (RTTHREAD_NAME_LEN). */
|
---|
144 | const char *pszName;
|
---|
145 |
|
---|
146 | /**
|
---|
147 | * Probing callback.
|
---|
148 | *
|
---|
149 | * Called in attempt to detect if user is currently running Desktop Environment
|
---|
150 | * which is compatible with the helper.
|
---|
151 | *
|
---|
152 | * @returns Helpercapabilities bitmask as described by VBOX_WAYLAND_HELPER_CAP_XXX.
|
---|
153 | */
|
---|
154 | DECLCALLBACKMEMBER(int, pfnProbe, (void));
|
---|
155 |
|
---|
156 | /**
|
---|
157 | * Initialization callback.
|
---|
158 | *
|
---|
159 | * @returns IPRT status code.
|
---|
160 | */
|
---|
161 | DECLCALLBACKMEMBER(int, pfnInit, (void));
|
---|
162 |
|
---|
163 | /**
|
---|
164 | * Termination callback.
|
---|
165 | *
|
---|
166 | * @returns IPRT status code.
|
---|
167 | */
|
---|
168 | DECLCALLBACKMEMBER(int, pfnTerm, (void));
|
---|
169 |
|
---|
170 | /**
|
---|
171 | * Callback to set host clipboard connection handle.
|
---|
172 | *
|
---|
173 | * @param pCtx Host service connection context.
|
---|
174 | */
|
---|
175 | DECLCALLBACKMEMBER(void, pfnSetClipboardCtx, (PVBGLR3SHCLCMDCTX pCtx));
|
---|
176 |
|
---|
177 | /**
|
---|
178 | * Callback to force guest to announce its clipboard content.
|
---|
179 | *
|
---|
180 | * @returns IPRT status code.
|
---|
181 | */
|
---|
182 | DECLCALLBACKMEMBER(int, pfnPopup, (void));
|
---|
183 |
|
---|
184 | PFNHOSTCLIPREPORTFMTS pfnHGClipReport;
|
---|
185 | PFNHOSTCLIPREAD pfnGHClipRead;
|
---|
186 |
|
---|
187 | } VBCLWAYLANDHELPER;
|
---|
188 |
|
---|
189 | namespace vbcl
|
---|
190 | {
|
---|
191 | /**
|
---|
192 | * This is abstract one-shot data type which can be set by writer and waited
|
---|
193 | * by reader in a thread-safe way.
|
---|
194 | *
|
---|
195 | * Method wait() will wait within predefined interval of time until
|
---|
196 | * value of this type will be changed to anything different from default
|
---|
197 | * value which is defined during initialization. Reader must compare
|
---|
198 | * returned value with what defaults() method returns in order to make
|
---|
199 | * sure that value was actually set by writer.
|
---|
200 | *
|
---|
201 | * Method reset() will atomically reset current value to defaults and
|
---|
202 | * return previous value. This is useful when writer has previously
|
---|
203 | * dynamically allocated chunk of memory and reader needs to deallocete
|
---|
204 | * it in the end.
|
---|
205 | */
|
---|
206 | template <class T> class Waitable
|
---|
207 | {
|
---|
208 | public:
|
---|
209 |
|
---|
210 | Waitable()
|
---|
211 | {};
|
---|
212 |
|
---|
213 | /**
|
---|
214 | * Initialize data type.
|
---|
215 | *
|
---|
216 | * @param default_value Default value, used while
|
---|
217 | * waiting for value change.
|
---|
218 | * @param timeoutMs Time interval to wait for
|
---|
219 | * value change before returning.
|
---|
220 | */
|
---|
221 | void init(T default_value, uint64_t timeoutMs)
|
---|
222 | {
|
---|
223 | m_Value = default_value;
|
---|
224 | m_Default = default_value;
|
---|
225 | m_TimeoutMs = timeoutMs;
|
---|
226 | }
|
---|
227 |
|
---|
228 | /**
|
---|
229 | * Atomically set value.
|
---|
230 | *
|
---|
231 | * @param value Value to set.
|
---|
232 | */
|
---|
233 | void set(T value)
|
---|
234 | {
|
---|
235 | ASMAtomicWriteU64(&m_Value, value);
|
---|
236 | }
|
---|
237 |
|
---|
238 | /**
|
---|
239 | * Atomically reset value to defaults and return previous value.
|
---|
240 | *
|
---|
241 | * @returns Value which was assigned before reset.
|
---|
242 | */
|
---|
243 | uint64_t reset()
|
---|
244 | {
|
---|
245 | return ASMAtomicXchgU64(&m_Value, m_Default);
|
---|
246 | }
|
---|
247 |
|
---|
248 | /**
|
---|
249 | * Wait until value will be changed from defaults and return it.
|
---|
250 | *
|
---|
251 | * @returns Current value.
|
---|
252 | */
|
---|
253 | T wait()
|
---|
254 | {
|
---|
255 | uint64_t tsStart = RTTimeMilliTS();
|
---|
256 |
|
---|
257 | while( (RTTimeMilliTS() - tsStart) < m_TimeoutMs
|
---|
258 | && (ASMAtomicReadU64(&m_Value)) == m_Default)
|
---|
259 | {
|
---|
260 | RTThreadSleep(VBCL_WAYLAND_RELAX_INTERVAL_MS);
|
---|
261 | }
|
---|
262 |
|
---|
263 | return m_Value;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /**
|
---|
267 | * Get default value which was set during initialization.
|
---|
268 | *
|
---|
269 | * @returns Default value.
|
---|
270 | */
|
---|
271 | T defaults()
|
---|
272 | {
|
---|
273 | return m_Default;
|
---|
274 | }
|
---|
275 |
|
---|
276 | protected:
|
---|
277 |
|
---|
278 | /** Value itself. */
|
---|
279 | uint64_t m_Value;
|
---|
280 | /** Default value. */
|
---|
281 | uint64_t m_Default;
|
---|
282 | /** Value change waiting timeout. */
|
---|
283 | uint64_t m_TimeoutMs;
|
---|
284 | };
|
---|
285 | }
|
---|
286 |
|
---|
287 | /**
|
---|
288 | * Initialize session.
|
---|
289 | *
|
---|
290 | * This function should be called only once, during initialization step.
|
---|
291 | *
|
---|
292 | * @param pSession A pointer to session data.
|
---|
293 | */
|
---|
294 | RTDECL(void) vbcl_wayland_session_init(vbcl_wl_session_t *pSession);
|
---|
295 |
|
---|
296 | /**
|
---|
297 | * Start new session.
|
---|
298 | *
|
---|
299 | * Attempt to change session state from IDLE to STARTED and
|
---|
300 | * execute initialization callback in between. If current
|
---|
301 | * session state is different from IDLE, state transition will
|
---|
302 | * not be possible and error will be returned.
|
---|
303 | *
|
---|
304 | * @returns IPRT status code.
|
---|
305 | * @param pSession Session object.
|
---|
306 | * @param enmType Session type.
|
---|
307 | * @param pfnStart Initialization callback.
|
---|
308 | * @param pvUser User data to pass to initialization callback.
|
---|
309 | */
|
---|
310 | RTDECL(int) vbcl_wayland_session_start(vbcl_wl_session_t *pSession,
|
---|
311 | vbcl_wl_session_type_t enmType,
|
---|
312 | PFNVBCLWLSESSIONCB pfnStart,
|
---|
313 | void *pvUser);
|
---|
314 |
|
---|
315 | /**
|
---|
316 | * Join session.
|
---|
317 | *
|
---|
318 | * Attempt to grab a reference to a session, execute provided
|
---|
319 | * callback while holding a reference and release reference.
|
---|
320 | * This function will fail if current session state is different
|
---|
321 | * from STARTED.
|
---|
322 | *
|
---|
323 | * @returns IPRT status code.
|
---|
324 | * @param pSession Session object.
|
---|
325 | * @param pfnJoin A callback to run while holding session reference.
|
---|
326 | * @param pvUser User data to pass to callback.
|
---|
327 | * @param pcszCallee Text tag which corresponds to calling function (only
|
---|
328 | * for logging)
|
---|
329 | */
|
---|
330 | RTDECL(int) vbcl_wayland_session_join_ex(vbcl_wl_session_t *pSession,
|
---|
331 | PFNVBCLWLSESSIONCB pfnJoin, void *pvUser,
|
---|
332 | const char *pcszCallee);
|
---|
333 |
|
---|
334 | /**
|
---|
335 | * Join session (wrapper for vbcl_wayland_session_join_ex).
|
---|
336 | */
|
---|
337 | #define vbcl_wayland_session_join(pSession, pfnJoin, pvUser) \
|
---|
338 | vbcl_wayland_session_join_ex(pSession, pfnJoin, pvUser, __func__)
|
---|
339 |
|
---|
340 | /**
|
---|
341 | * End session.
|
---|
342 | *
|
---|
343 | * Attempt to wait until session is no longer in use, execute
|
---|
344 | * terminating callback and reset session to IDLE state.
|
---|
345 | *
|
---|
346 | * @returns IPRT status code.
|
---|
347 | * @param pSession Session object.
|
---|
348 | * @param pfnEnd Termination callback.
|
---|
349 | * @param pvUser User data to pass to termination callback.
|
---|
350 | */
|
---|
351 | RTDECL(int) vbcl_wayland_session_end(vbcl_wl_session_t *pSession,
|
---|
352 | PFNVBCLWLSESSIONCB pfnEnd, void *pvUser);
|
---|
353 |
|
---|
354 | /**
|
---|
355 | * Check if session was started.
|
---|
356 | *
|
---|
357 | * @returns True if session is started, False otherwise.
|
---|
358 | * @param pSession Session object.
|
---|
359 | */
|
---|
360 | RTDECL(bool) vbcl_wayland_session_is_started(vbcl_wl_session_t *pSession);
|
---|
361 |
|
---|
362 | /** Wayland helper which uses GTK library. */
|
---|
363 | extern const VBCLWAYLANDHELPER g_WaylandHelperGtk;
|
---|
364 | /** Wayland helper which uses Data Control Protocol. */
|
---|
365 | extern const VBCLWAYLANDHELPER g_WaylandHelperDcp;
|
---|
366 |
|
---|
367 | #endif /* !GA_INCLUDED_SRC_x11_VBoxClient_wayland_helper_h */
|
---|