Changeset 81843 in vbox for trunk/src/VBox/Additions/x11/VBoxClient
- Timestamp:
- Nov 14, 2019 4:30:44 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp
r81820 r81843 46 46 struct _SHCLCONTEXT 47 47 { 48 /** Client ID for the clipboard subsystem */ 49 uint32_t client; 50 51 /** Pointer to the X11 clipboard backend */ 52 CLIPBACKEND *pBackend; 48 /** Client command context */ 49 VBGLR3SHCLCMDCTX CmdCtx; 50 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 51 /** Associated transfer data. */ 52 SHCLTRANSFERCTX TransferCtx; 53 #endif 54 /** Pointer to the X11 clipboard backend. */ 55 CLIPBACKEND *pBackend; 53 56 }; 54 57 55 58 /** Only one client is supported. There seems to be no need for more clients. */ 56 static SHCLCONTEXT g_ctx; 57 58 59 /** 60 * Transfer clipboard data from the guest to the host. 61 * 62 * @returns VBox result code 63 * @param u32Format The format of the data being sent 64 * @param pv Pointer to the data being sent 65 * @param cb Size of the data being sent in bytes 66 */ 67 static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb) 68 { 69 int rc; 70 LogFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb)); 71 rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb); 72 LogFlowFuncLeaveRC(rc); 73 return rc; 74 } 59 static SHCLCONTEXT g_Ctx; 75 60 76 61 … … 79 64 * 80 65 * @returns VBox result code 81 * @param pCtx Our context information82 * @param u32Format The format of the data being requested83 * @param ppv On success and if pcb > 0, this will point to a buffer84 * to be freed with RTMemFree containing the data read.85 * @param pcb On success, this contains the number of bytes of data86 * returned87 */ 88 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)66 * @param pCtx Our context information. 67 * @param Format The format of the data being requested. 68 * @param ppv On success and if pcb > 0, this will point to a buffer 69 * to be freed with RTMemFree containing the data read. 70 * @param pcb On success, this contains the number of bytes of data 71 * returned. 72 */ 73 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb) 89 74 { 90 75 RT_NOREF(pCtx); 76 77 LogFlowFunc(("Format=0x%x\n", Format)); 78 91 79 int rc = VINF_SUCCESS; 92 uint32_t cb = 1024; 93 void *pv = RTMemAlloc(cb); 94 95 *ppv = 0; 96 LogFlowFunc(("u32Format=%u\n", u32Format)); 97 if (RT_UNLIKELY(!pv)) 98 rc = VERR_NO_MEMORY; 99 if (RT_SUCCESS(rc)) 100 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); 101 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) 102 *ppv = pv; 103 /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a 104 * larger buffer. The size of the buffer needed is placed in *pcb. 105 * So we start all over again. */ 106 if (rc == VINF_BUFFER_OVERFLOW) 107 { 108 cb = *pcb; 109 RTMemFree(pv); 110 pv = RTMemAlloc(cb); 111 if (RT_UNLIKELY(!pv)) 80 81 uint32_t cbRead = 0; 82 83 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 84 if (Format == VBOX_SHCL_FMT_URI_LIST) 85 { 86 //rc = VbglR3ClipboardRootListRead() 87 } 88 else 89 #endif 90 { 91 SHCLDATABLOCK dataBlock; 92 RT_ZERO(dataBlock); 93 94 dataBlock.uFormat = Format; 95 dataBlock.cbData = _4K; 96 dataBlock.pvData = RTMemAlloc(dataBlock.cbData); 97 if (dataBlock.pvData) 98 { 99 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead); 100 } 101 else 112 102 rc = VERR_NO_MEMORY; 113 if (RT_SUCCESS(rc)) 114 rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); 115 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) 116 *ppv = pv; 117 } 118 /* Catch other errors. This also catches the case in which the buffer was 119 * too small a second time, possibly because the clipboard contents 120 * changed half-way through the operation. Since we can't say whether or 121 * not this is actually an error, we just return size 0. 122 */ 123 if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc)) 124 { 125 *pcb = 0; 126 if (pv != NULL) 127 RTMemFree(pv); 128 } 103 104 /* 105 * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a 106 * larger buffer. The size of the buffer needed is placed in *pcb. 107 * So we start all over again. 108 */ 109 if (rc == VINF_BUFFER_OVERFLOW) 110 { 111 /* cbRead contains the size required. */ 112 113 dataBlock.cbData = cbRead; 114 dataBlock.pvData = RTMemRealloc(dataBlock.pvData, cbRead); 115 if (dataBlock.pvData) 116 { 117 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead); 118 if ( RT_SUCCESS(rc) 119 && (rc != VINF_BUFFER_OVERFLOW)) 120 { 121 *pcb = cbRead; /* Actual bytes read. */ 122 *ppv = dataBlock.pvData; 123 } 124 } 125 else 126 rc = VERR_NO_MEMORY; 127 } 128 129 /* 130 * Catch other errors. This also catches the case in which the buffer was 131 * too small a second time, possibly because the clipboard contents 132 * changed half-way through the operation. Since we can't say whether or 133 * not this is actually an error, we just return size 0. 134 */ 135 if ( RT_FAILURE(rc) 136 || (VINF_BUFFER_OVERFLOW == rc)) 137 { 138 RTMemFree(dataBlock.pvData); 139 } 140 } 141 129 142 LogFlowFuncLeaveRC(rc); 130 if (RT_SUCCESS(rc))131 LogFlow((" *pcb=%d\n", *pcb));132 143 return rc; 133 144 } 134 145 135 /** Opaque data structure describing a request from the host for clipboard 146 /** 147 * Opaque data structure describing a request from the host for clipboard 136 148 * data, passed in when the request is forwarded to the X11 backend so that 137 * it can be completed correctly. */ 149 * it can be completed correctly. 150 */ 138 151 struct _CLIPREADCBREQ 139 152 { 140 153 /** The data format that was requested. */ 141 uint32_t u32Format;154 SHCLFORMAT Format; 142 155 }; 143 156 … … 146 159 * 147 160 * @param pCtx Our context information. 148 * @param u32FormatsThe formats to report.149 */ 150 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)161 * @param Formats The formats to report. 162 */ 163 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats) 151 164 { 152 165 RT_NOREF(pCtx); 153 166 154 LogFlowFunc(("u32Formats=%RU32\n", u32Formats)); 155 156 int rc = VbglR3ClipboardFormatsReport(g_ctx.client, u32Formats); 157 RT_NOREF(rc); 158 159 LogFlowFuncLeaveRC(rc); 160 } 161 162 /** This is called by the backend to tell us that a request for data from 167 LogFlowFunc(("Formats=0x%x\n", Formats)); 168 169 SHCLFORMATDATA formatData; 170 RT_ZERO(formatData); 171 172 formatData.Formats = Formats; 173 174 int rc2 = VbglR3ClipboardFormatsReportEx(&pCtx->CmdCtx, &formatData); 175 RT_NOREF(rc2); 176 LogFlowFuncLeaveRC(rc2); 177 } 178 179 /** 180 * This is called by the backend to tell us that a request for data from 163 181 * X11 has completed. 164 * @param pCtx Our context information165 * @param rc the iprt result code of the request166 * @param pReq the request structure that we passed in when we started167 * the request. We RTMemFree() this in this function.168 * @param pv the clipboard data returned from X11 if the request169 * succeeded (see @a rc)170 * @param cb the size of the data in @a pv182 * 183 * @param pCtx Our context information. 184 * @param rc The IPRT result code of the request. 185 * @param pReq The request structure that we passed in when we started 186 * the request. We RTMemFree() this in this function. 187 * @param pv The clipboard data returned from X11 if the request succeeded (see @a rc). 188 * @param cb The size of the data in @a pv. 171 189 */ 172 190 DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb) 173 191 { 174 192 RT_NOREF(pCtx); 193 194 LogFlowFunc(("rc=%Rrc, Format=0x%x, pv=%p, cb=%RU32\n", rc, pReq->Format, pv, cb)); 195 196 SHCLDATABLOCK dataBlock; 197 RT_ZERO(dataBlock); 198 199 dataBlock.uFormat = pReq->Format; 200 175 201 if (RT_SUCCESS(rc)) 176 vboxClipboardSendData(pReq->u32Format, pv, cb); 177 else 178 vboxClipboardSendData(0, NULL, 0); 202 { 203 dataBlock.pvData = pv; 204 dataBlock.cbData = cb; 205 } 206 207 int rc2 = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, &dataBlock); 208 RT_NOREF(rc2); 209 179 210 RTMemFree(pReq); 211 212 LogFlowFuncLeaveRC(rc2); 180 213 } 181 214 … … 183 216 * Connect the guest clipboard to the host. 184 217 * 185 * @returns VBox status code 218 * @returns VBox status code. 186 219 */ 187 220 static int vboxClipboardConnect(void) … … 189 222 LogFlowFuncEnter(); 190 223 191 /* Sanity */192 AssertReturn(g_ctx.client == 0, VERR_WRONG_ORDER);193 AssertReturn(g_ctx.pBackend == NULL, VERR_WRONG_ORDER);194 195 224 int rc; 196 225 197 g_ ctx.pBackend = ClipConstructX11(&g_ctx, false);198 if (g_ ctx.pBackend)199 { 200 rc = ClipStartX11(g_ ctx.pBackend, false /* grab */);226 g_Ctx.pBackend = ClipConstructX11(&g_Ctx, false); 227 if (g_Ctx.pBackend) 228 { 229 rc = ClipStartX11(g_Ctx.pBackend, false /* grab */); 201 230 if (RT_SUCCESS(rc)) 202 231 { 203 rc = VbglR3ClipboardConnect(&g_ctx.client); 204 if (RT_SUCCESS(rc)) 205 { 206 Assert(g_ctx.client); 207 } 208 else 209 VBClLogError("Error connecting to host, rc=%Rrc\n", rc); 232 rc = VbglR3ClipboardConnectEx(&g_Ctx.CmdCtx); 210 233 } 211 234 } … … 213 236 rc = VERR_NO_MEMORY; 214 237 215 if (rc != VINF_SUCCESS && g_ctx.pBackend) 216 ClipDestructX11(g_ctx.pBackend); 238 if (RT_FAILURE(rc)) 239 { 240 VBClLogError("Error connecting to host service, rc=%Rrc\n", rc); 241 242 VbglR3ClipboardDisconnectEx(&g_Ctx.CmdCtx); 243 ClipDestructX11(g_Ctx.pBackend); 244 } 217 245 218 246 LogFlowFuncLeaveRC(rc); … … 225 253 int vboxClipboardMain(void) 226 254 { 255 LogRel2(("Worker loop running\n")); 256 227 257 int rc; 228 LogFlowFunc(("Starting guest clipboard service\n")); 229 bool fExiting = false; 230 231 while (!fExiting) 232 { 233 uint32_t Msg; 234 uint32_t fFormats; 235 rc = VbglR3ClipboardGetHostMsgOld(g_ctx.client, &Msg, &fFormats); 236 if (RT_SUCCESS(rc)) 237 { 238 switch (Msg) 239 { 240 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: 241 { 242 /* The host has announced available clipboard formats. 243 * Save the information so that it is available for 244 * future requests from guest applications. 245 */ 246 LogFlowFunc(("VBOX_SHCL_HOST_MSG_FORMATS_WRITE fFormats=%x\n", fFormats)); 247 ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats); 248 break; 249 } 250 251 case VBOX_SHCL_HOST_MSG_READ_DATA: 258 259 SHCLCONTEXT *pCtx = &g_Ctx; 260 261 bool fShutdown = false; 262 263 /* The thread waits for incoming messages from the host. */ 264 for (;;) 265 { 266 PVBGLR3CLIPBOARDEVENT pEvent = NULL; 267 268 LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n", 269 pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures)); 270 271 if (pCtx->CmdCtx.fUseLegacyProtocol) 272 { 273 uint32_t uMsg; 274 uint32_t uFormats; 275 276 rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.uClientID, &uMsg, &uFormats); 277 if (RT_FAILURE(rc)) 278 { 279 if (rc == VERR_INTERRUPTED) 280 break; 281 282 LogFunc(("Error getting host message, rc=%Rrc\n", rc)); 283 } 284 else 285 { 286 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 287 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY); 288 289 switch (uMsg) 290 { 291 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT: 292 { 293 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS; 294 pEvent->u.ReportedFormats.Formats = uFormats; 295 break; 296 } 297 298 case VBOX_SHCL_HOST_MSG_READ_DATA: 299 { 300 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA; 301 pEvent->u.ReadData.uFmt = uFormats; 302 break; 303 } 304 305 case VBOX_SHCL_HOST_MSG_QUIT: 306 { 307 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT; 308 break; 309 } 310 311 default: 312 rc = VERR_NOT_SUPPORTED; 313 break; 314 } 315 316 if (RT_SUCCESS(rc)) 317 { 318 /* Copy over our command context to the event. */ 319 pEvent->cmdCtx = pCtx->CmdCtx; 320 } 321 } 322 } 323 else /* Host service has peeking for messages support. */ 324 { 325 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT)); 326 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY); 327 328 uint32_t uMsg = 0; 329 uint32_t cParms = 0; 330 rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */); 331 if (RT_SUCCESS(rc)) 332 { 333 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 334 rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent); 335 #else 336 rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent); 337 #endif 338 } 339 } 340 341 if (RT_FAILURE(rc)) 342 { 343 LogFlowFunc(("Getting next event failed with %Rrc\n", rc)); 344 345 VbglR3ClipboardEventFree(pEvent); 346 pEvent = NULL; 347 348 if (fShutdown) 349 break; 350 351 /* Wait a bit before retrying. */ 352 RTThreadSleep(1000); 353 continue; 354 } 355 else 356 { 357 AssertPtr(pEvent); 358 LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType)); 359 360 switch (pEvent->enmType) 361 { 362 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS: 363 { 364 ClipAnnounceFormatToX11(g_Ctx.pBackend, pEvent->u.ReportedFormats.Formats); 365 break; 366 } 367 368 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA: 252 369 { 253 370 /* The host needs data in the specified format. */ 254 LogFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));255 371 CLIPREADCBREQ *pReq; 256 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof( *pReq));257 if ( !pReq)372 pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ)); 373 if (pReq) 258 374 { 259 rc = VERR_NO_MEMORY;260 fExiting = true;375 pReq->Format = pEvent->u.ReadData.uFmt; 376 ClipReadDataFromX11(g_Ctx.pBackend, pReq->Format, pReq); 261 377 } 262 378 else 263 { 264 pReq->u32Format = fFormats; 265 ClipReadDataFromX11(g_ctx.pBackend, fFormats, 266 pReq); 267 } 268 break; 269 } 270 271 case VBOX_SHCL_HOST_MSG_QUIT: 272 { 273 /* The host is terminating. */ 274 LogFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n")); 275 if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend))) 276 ClipDestructX11(g_ctx.pBackend); 277 fExiting = true; 379 rc = VERR_NO_MEMORY; 380 break; 381 } 382 383 case VBGLR3CLIPBOARDEVENTTYPE_QUIT: 384 { 385 LogRel2(("Host requested termination\n")); 386 fShutdown = true; 387 break; 388 } 389 390 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 391 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS: 392 { 393 /* Nothing to do here. */ 394 rc = VINF_SUCCESS; 395 break; 396 } 397 #endif 398 case VBGLR3CLIPBOARDEVENTTYPE_NONE: 399 { 400 /* Nothing to do here. */ 401 rc = VINF_SUCCESS; 278 402 break; 279 403 } … … 281 405 default: 282 406 { 283 VBClLogInfo("Unsupported message from host (%RU32)\n", Msg); 284 break; 285 } 286 } 287 } 288 289 LogFlow(("processed host event rc = %d\n", rc)); 290 } 407 AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED); 408 } 409 } 410 411 if (pEvent) 412 { 413 VbglR3ClipboardEventFree(pEvent); 414 pEvent = NULL; 415 } 416 } 417 418 if (fShutdown) 419 break; 420 } 421 422 LogRel(("Worker loop ended\n")); 423 291 424 LogFlowFuncLeaveRC(rc); 292 425 return rc; … … 343 476 }; 344 477 345 struct VBCLSERVICE **VBClGetClipboardService( )478 struct VBCLSERVICE **VBClGetClipboardService(void) 346 479 { 347 480 struct CLIPBOARDSERVICE *pService =
Note:
See TracChangeset
for help on using the changeset viewer.