Changeset 101878 in vbox for trunk/src/VBox/Additions/x11/VBoxClient/wayland.cpp
- Timestamp:
- Nov 6, 2023 3:36:24 PM (15 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/wayland.cpp
r100248 r101878 26 26 */ 27 27 28 #include <iprt/asm.h> 29 #include <iprt/thread.h> 30 31 #include <VBox/HostServices/GuestPropertySvc.h> 32 28 33 #include "VBoxClient.h" 34 #include "clipboard.h" 29 35 #include "wayland-helper.h" 36 37 /** Polling interval for input focus monitoring task. */ 38 #define VBCL_WAYLAND_WAIT_HOST_FOCUS_TIMEOUT_MS (250) 39 /** Relax interval for input focus monitoring task. */ 40 #define VBCL_WAYLAND_WAIT_HOST_FOCUS_RELAX_MS (100) 30 41 31 42 /** List of available Wayland Desktop Environment helpers. Sorted in order of preference. */ 32 43 static const VBCLWAYLANDHELPER *g_apWaylandHelpers[] = 33 44 { 45 &g_WaylandHelperDcp, /* Device Control Protocol helper. */ 34 46 &g_WaylandHelperGtk, /* GTK helper. */ 35 &g_WaylandHelperDcp, /* Device Control Protocol helper. */36 47 NULL, /* Terminate list. */ 37 48 }; 38 49 50 /** Global flag to tell service to go shutdown when needed. */ 51 static bool volatile g_fShutdown = false; 52 39 53 /** Selected helpers for Clipboard and Drag-and-Drop. */ 40 static const VBCLWAYLANDHELPER *g_pWaylandHelperHelperClipboard = NULL; 41 static const VBCLWAYLANDHELPER *g_pWaylandHelperHelperDnd = NULL; 54 static const VBCLWAYLANDHELPER *g_pWaylandHelperClipboard = NULL; 55 static const VBCLWAYLANDHELPER *g_pWaylandHelperDnd = NULL; 56 57 /** Corresponding threads for host events handling. */ 58 static RTTHREAD g_ClipboardThread; 59 static RTTHREAD g_DndThread; 60 static RTTHREAD g_HostInputFocusThread; 61 62 /** 63 * Worker for Shared Clipboard events from host. 64 * 65 * @returns IPRT status code. 66 * @param hThreadSelf IPRT thread handle. 67 * @param pvUser User data (unused). 68 */ 69 static DECLCALLBACK(int) vbclWaylandClipboardWorker(RTTHREAD hThreadSelf, void *pvUser) 70 { 71 SHCLCONTEXT ctx; 72 int rc; 73 74 RT_NOREF(pvUser); 75 76 RT_ZERO(ctx); 77 78 /* Connect to the host service. */ 79 rc = VbglR3ClipboardConnectEx(&ctx.CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID); 80 /* Notify parent thread. */ 81 RTThreadUserSignal(hThreadSelf); 82 83 if (RT_SUCCESS(rc)) 84 { 85 /* Provide helper with host clipboard service connection handle. */ 86 g_pWaylandHelperClipboard->pfnSetClipboardCtx(&ctx.CmdCtx); 87 88 /* Process host events. */ 89 while (!ASMAtomicReadBool(&g_fShutdown)) 90 { 91 rc = VBClClipboardReadHostEvent(&ctx, g_pWaylandHelperClipboard->pfnHGClipReport, 92 g_pWaylandHelperClipboard->pfnGHClipRead); 93 if (RT_FAILURE(rc)) 94 { 95 VBClLogInfo("cannot process host clipboard event, rc=%Rrc\n", rc); 96 RTThreadSleep(RT_MS_1SEC / 2); 97 } 98 } 99 100 VbglR3ClipboardDisconnectEx(&ctx.CmdCtx); 101 } 102 103 VBClLogVerbose(2, "clipboard thread, rc=%Rrc\n", rc); 104 105 return rc; 106 } 107 108 /** 109 * Worker for Drag-and-Drop events from host. 110 * 111 * @returns IPRT status code. 112 * @param hThreadSelf IPRT thread handle. 113 * @param pvUser User data (unused). 114 */ 115 static DECLCALLBACK(int) vbclWaylandDndWorker(RTTHREAD hThreadSelf, void *pvUser) 116 { 117 RT_NOREF(pvUser); 118 119 RTThreadUserSignal(hThreadSelf); 120 return VINF_SUCCESS; 121 } 122 123 /** 124 * Worker for VM window focus change polling thread. 125 * 126 * Some Wayland helpers need to be notified about VM 127 * window focus change events. This is needed in order to 128 * ask about, for example, if guest clipboard content was 129 * changed since last user interaction. Such guest are not 130 * able to notify host about clipboard content change and 131 * needed to be asked implicitly. 132 * 133 * @returns IPRT status code. 134 * @param hThreadSelf IPRT thread handle. 135 * @param pvUser User data (unused). 136 */ 137 static DECLCALLBACK(int) vbclWaylandHostInputFocusWorker(RTTHREAD hThreadSelf, void *pvUser) 138 { 139 int rc; 140 141 RT_NOREF(pvUser); 142 143 HGCMCLIENTID idClient; 144 145 rc = VbglR3GuestPropConnect(&idClient); 146 147 RTThreadUserSignal(hThreadSelf); 148 149 if (RT_SUCCESS(rc)) 150 { 151 while (!ASMAtomicReadBool(&g_fShutdown)) 152 { 153 static char achBuf[GUEST_PROP_MAX_NAME_LEN]; 154 char *pszName = NULL; 155 char *pszValue = NULL; 156 char *pszFlags = NULL; 157 bool fWasDeleted = false; 158 uint64_t u64Timestamp = 0; 159 160 rc = VbglR3GuestPropWait(idClient, VBOX_GUI_FOCUS_CHANGE_GUEST_PROP_NAME, achBuf, sizeof(achBuf), u64Timestamp, 161 VBCL_WAYLAND_WAIT_HOST_FOCUS_TIMEOUT_MS, &pszName, &pszValue, &u64Timestamp, 162 &pszFlags, NULL, &fWasDeleted); 163 if (RT_SUCCESS(rc)) 164 { 165 uint32_t fFlags = 0; 166 167 VBClLogVerbose(1, "guest property change: name: %s, val: %s, flags: %s, fWasDeleted: %RTbool\n", 168 pszName, pszValue, pszFlags, fWasDeleted); 169 170 if (RT_SUCCESS(GuestPropValidateFlags(pszFlags, &fFlags))) 171 { 172 if (RTStrNCmp(pszName, VBOX_GUI_FOCUS_CHANGE_GUEST_PROP_NAME, GUEST_PROP_MAX_NAME_LEN) == 0) 173 { 174 if (fFlags & GUEST_PROP_F_RDONLYGUEST) 175 { 176 if (RT_VALID_PTR(g_pWaylandHelperClipboard)) 177 { 178 if (RTStrNCmp(pszValue, "0", GUEST_PROP_MAX_NAME_LEN) == 0) 179 { 180 rc = g_pWaylandHelperClipboard->pfnPopup(); 181 VBClLogVerbose(1, "trigger popup, rc=%Rrc\n", rc); 182 } 183 } 184 else 185 VBClLogVerbose(1, "will not trigger popup\n"); 186 } 187 else 188 VBClLogError("property has invalid attributes\n"); 189 } 190 else 191 VBClLogVerbose(1, "unknown property name '%s'\n", pszName); 192 193 } else 194 VBClLogError("guest property change: name: %s, val: %s, flags: %s, fWasDeleted: %RTbool: bad flags\n", 195 pszName, pszValue, pszFlags, fWasDeleted); 196 197 } else if ( rc != VERR_TIMEOUT 198 && rc != VERR_INTERRUPTED) 199 { 200 VBClLogError("error on waiting guest property notification, rc=%Rrc\n", rc); 201 RTThreadSleep(VBCL_WAYLAND_WAIT_HOST_FOCUS_RELAX_MS); 202 } 203 } 204 } 205 206 return rc; 207 } 208 42 209 43 210 /** … … 68 235 /* Try Clipboard helper. */ 69 236 if ( fCaps & VBOX_WAYLAND_HELPER_CAP_CLIPBOARD 70 && !RT_VALID_PTR(g_pWaylandHelper HelperClipboard))237 && !RT_VALID_PTR(g_pWaylandHelperClipboard)) 71 238 { 72 239 if (RT_VALID_PTR(g_apWaylandHelpers[idxHelper]->pfnInit)) … … 74 241 rc = g_apWaylandHelpers[idxHelper]->pfnInit(); 75 242 if (RT_SUCCESS(rc)) 76 g_pWaylandHelper HelperClipboard = g_apWaylandHelpers[idxHelper];243 g_pWaylandHelperClipboard = g_apWaylandHelpers[idxHelper]; 77 244 else 78 VBClLogError("Wayland helper '%s' cannot be initialized, skipping"); 245 VBClLogError("Wayland helper '%s' cannot be initialized, skipping\n", 246 g_apWaylandHelpers[idxHelper]->pszName); 79 247 } 248 else 249 VBClLogVerbose(1, "Wayland helper '%s' has no initializer, skipping\n", 250 g_apWaylandHelpers[idxHelper]->pszName); 80 251 } 81 252 82 253 /* Try DnD helper. */ 83 254 if ( fCaps & VBOX_WAYLAND_HELPER_CAP_DND 84 && !RT_VALID_PTR(g_pWaylandHelper HelperDnd))255 && !RT_VALID_PTR(g_pWaylandHelperDnd)) 85 256 { 86 257 if (RT_VALID_PTR(g_apWaylandHelpers[idxHelper]->pfnInit)) … … 88 259 rc = g_apWaylandHelpers[idxHelper]->pfnInit(); 89 260 if (RT_SUCCESS(rc)) 90 g_pWaylandHelper HelperDnd = g_apWaylandHelpers[idxHelper];261 g_pWaylandHelperDnd = g_apWaylandHelpers[idxHelper]; 91 262 else 92 VBClLogError("Wayland helper '%s' cannot be initialized, skipping"); 263 VBClLogError("Wayland helper '%s' cannot be initialized, skipping\n", 264 g_apWaylandHelpers[idxHelper]->pszName); 93 265 } 266 else 267 VBClLogVerbose(1, "Wayland helper '%s' has no initializer, skipping\n", 268 g_apWaylandHelpers[idxHelper]->pszName); 94 269 } 95 270 } 96 271 97 272 /* See if we found all the needed helpers. */ 98 if ( RT_VALID_PTR(g_pWaylandHelper HelperClipboard)99 && RT_VALID_PTR(g_pWaylandHelper HelperDnd))273 if ( RT_VALID_PTR(g_pWaylandHelperClipboard) 274 && RT_VALID_PTR(g_pWaylandHelperDnd)) 100 275 break; 101 276 … … 104 279 105 280 /* Check result. */ 106 if (RT_VALID_PTR(g_pWaylandHelper HelperClipboard))107 VBClLogInfo("found Wayland Shared Clipboard helper '%s'\n", g_pWaylandHelper HelperClipboard->pszName);281 if (RT_VALID_PTR(g_pWaylandHelperClipboard)) 282 VBClLogInfo("found Wayland Shared Clipboard helper '%s'\n", g_pWaylandHelperClipboard->pszName); 108 283 else 109 284 VBClLogError("Wayland Shared Clipboard helper not found, clipboard sharing not possible\n"); 110 285 111 286 /* Check result. */ 112 if (RT_VALID_PTR(g_pWaylandHelper HelperDnd))113 VBClLogInfo("found Wayland Drag-and-Drop helper '%s'\n", g_pWaylandHelper HelperDnd->pszName);287 if (RT_VALID_PTR(g_pWaylandHelperDnd)) 288 VBClLogInfo("found Wayland Drag-and-Drop helper '%s'\n", g_pWaylandHelperDnd->pszName); 114 289 else 115 290 VBClLogError("Wayland Drag-and-Drop helper not found, drag-and-drop not possible\n"); … … 123 298 static DECLCALLBACK(int) vbclWaylandWorker(bool volatile *pfShutdown) 124 299 { 300 int rc = VINF_SUCCESS; 301 125 302 RT_NOREF(pfShutdown); 126 return VERR_NOT_SUPPORTED; 303 304 VBClLogVerbose(1, "starting wayland worker thread\n"); 305 306 /* Start event loop for clipboard events processing from host. */ 307 if (RT_VALID_PTR(g_pWaylandHelperClipboard)) 308 { 309 rc = VBClClipboardThreadStart(&g_ClipboardThread, vbclWaylandClipboardWorker, "wl-clip", NULL); 310 VBClLogVerbose(1, "clipboard thread started, rc=%Rrc\n", rc); 311 } 312 313 /* Start event loop for DnD events processing from host. */ 314 if ( RT_SUCCESS(rc) 315 && RT_VALID_PTR(g_pWaylandHelperDnd)) 316 { 317 rc = VBClClipboardThreadStart(&g_DndThread, vbclWaylandDndWorker, "wl-dnd", NULL); 318 VBClLogVerbose(1, "DnD thread started, rc=%Rrc\n", rc); 319 } 320 321 /* Start polling host input focus events. */ 322 if (RT_SUCCESS(rc)) 323 { 324 rc = VBClClipboardThreadStart(&g_HostInputFocusThread, vbclWaylandHostInputFocusWorker, "wl-focus", NULL); 325 VBClLogVerbose(1, "host input focus polling thread started, rc=%Rrc\n", rc); 326 } 327 328 /* Notify parent thread that we are successfully started. */ 329 RTThreadUserSignal(RTThreadSelf()); 330 331 if (RT_SUCCESS(rc)) 332 { 333 int rcThread = VINF_SUCCESS; 334 335 if (RT_VALID_PTR(g_pWaylandHelperClipboard)) 336 { 337 rc = RTThreadWait(g_ClipboardThread, RT_INDEFINITE_WAIT, &rcThread); 338 VBClLogVerbose(1, "clipboard thread finished, rc=%Rrc, rcThread=%Rrc\n", rc, rcThread); 339 } 340 341 if ( RT_SUCCESS(rc) 342 && RT_VALID_PTR(g_pWaylandHelperDnd)) 343 { 344 rc = RTThreadWait(g_DndThread, RT_INDEFINITE_WAIT, &rcThread); 345 VBClLogVerbose(1, "DnD thread finished, rc=%Rrc, rcThread=%Rrc\n", rc, rcThread); 346 } 347 348 if (RT_SUCCESS(rc)) 349 { 350 rc = RTThreadWait(g_HostInputFocusThread, RT_INDEFINITE_WAIT, &rcThread); 351 VBClLogVerbose(1, "host input focus polling thread finished, rc=%Rrc, rcThread=%Rrc\n", rc, rcThread); 352 } 353 } 354 355 VBClLogVerbose(1, "wayland worker thread finished, rc=%Rrc\n", rc); 356 357 return rc; 127 358 } 128 359 … … 132 363 static DECLCALLBACK(void) vbclWaylandStop(void) 133 364 { 365 VBClLogVerbose(1, "terminating wayland service: clipboard & DnD host event loops\n"); 366 367 /* This callback can be called twice (not good, needs to be fixed). Already was shut down? */ 368 if (ASMAtomicReadBool(&g_fShutdown)) 369 return; 370 371 ASMAtomicWriteBool(&g_fShutdown, true); 372 373 if (RT_VALID_PTR(g_pWaylandHelperClipboard)) 374 RTThreadPoke(g_ClipboardThread); 375 376 if (RT_VALID_PTR(g_pWaylandHelperDnd)) 377 RTThreadPoke(g_DndThread); 134 378 } 135 379 … … 139 383 static DECLCALLBACK(int) vbclWaylandTerm(void) 140 384 { 141 return VERR_NOT_SUPPORTED; 385 int rc = VINF_SUCCESS; 386 387 VBClLogVerbose(1, "shutting down wayland service: clipboard & DnD helpers\n"); 388 389 if ( RT_VALID_PTR(g_pWaylandHelperClipboard) 390 && RT_VALID_PTR(g_pWaylandHelperClipboard->pfnTerm)) 391 rc = g_pWaylandHelperClipboard->pfnTerm(); 392 393 if ( RT_SUCCESS(rc) 394 && RT_VALID_PTR(g_pWaylandHelperDnd) 395 && RT_VALID_PTR(g_pWaylandHelperDnd->pfnTerm)) 396 rc = g_pWaylandHelperDnd->pfnTerm(); 397 398 return rc; 142 399 } 143 400
Note:
See TracChangeset
for help on using the changeset viewer.