[100246] | 1 | /* $Id: wayland-helper.h 101878 2023-11-06 15:36:24Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[101878] | 3 | * Guest Additions - Definitions for Wayland helpers.
|
---|
[100246] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (C) 2006-2023 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 |
|
---|
[101878] | 34 | #include <iprt/asm.h>
|
---|
| 35 | #include <iprt/time.h>
|
---|
[100246] | 36 |
|
---|
[101878] | 37 | #include <VBox/VBoxGuestLib.h>
|
---|
| 38 | #include <VBox/GuestHost/clipboard-helper.h>
|
---|
[100246] | 39 |
|
---|
[101878] | 40 | #include "clipboard.h"
|
---|
| 41 |
|
---|
[100246] | 42 | /** Helper capabilities list. */
|
---|
[101878] | 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. */
|
---|
[100246] | 63 | typedef enum
|
---|
| 64 | {
|
---|
[101878] | 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;
|
---|
[100246] | 74 |
|
---|
[101878] | 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 |
|
---|
[100246] | 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 | *
|
---|
[101878] | 152 | * @returns Helpercapabilities bitmask as described by VBOX_WAYLAND_HELPER_CAP_XXX.
|
---|
[100246] | 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 |
|
---|
[101878] | 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 |
|
---|
[100246] | 187 | } VBCLWAYLANDHELPER;
|
---|
| 188 |
|
---|
[101878] | 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 |
|
---|
[100246] | 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 */
|
---|