/** * Connect the guest clipboard to the host. * * @returns VBox status code */ int vboxClipboardConnect(void) { int rc = VINF_SUCCESS; LogRelFlowFunc(("\n")); /* Sanity */ AssertReturn(g_ctx.client == 0, VERR_WRONG_ORDER); g_ctx.pBackend = ClipConstructX11(&g_ctx, false); if (!g_ctx.pBackend) rc = VERR_NO_MEMORY; if (RT_SUCCESS(rc)) rc = ClipStartX11(g_ctx.pBackend); if (RT_SUCCESS(rc)) { rc = VbglR3ClipboardConnect(&g_ctx.client); if (RT_FAILURE(rc)) LogRel(("Error connecting to host. rc=%Rrc\n", rc)); else if (!g_ctx.client) { LogRel(("Invalid client ID of 0\n")); rc = VERR_NOT_SUPPORTED; } } if (rc != VINF_SUCCESS && g_ctx.pBackend) ClipDestructX11(g_ctx.pBackend); LogRelFlowFunc(("g_ctx.client=%u rc=%Rrc\n", g_ctx.client, rc)); return rc; }
/** * Tell the host that new clipboard formats are available. * * @param u32Formats The formats to advertise */ void ClipReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Formats) { int rc; LogRelFlowFunc(("u32Formats=%d\n", u32Formats)); rc = VbglR3ClipboardReportFormats(g_ctx.client, u32Formats); LogRelFlowFunc(("rc=%Rrc\n", rc)); }
status_t VBoxClipboardService::_ServiceThread() { printf("VBoxClipboardService::%s()\n", __FUNCTION__); /* The thread waits for incoming messages from the host. */ for (;;) { uint32_t u32Msg; uint32_t u32Formats; int rc = VbglR3ClipboardGetHostMsg(fClientId, &u32Msg, &u32Formats); if (RT_SUCCESS(rc)) { switch (u32Msg) { case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS: { /* * The host has announced available clipboard formats. Forward * the information to the handler. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS u32Formats=%x\n", u32Formats)); BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS); msg.AddInt32("Formats", (uint32)u32Formats); Looper()->PostMessage(&msg, this); break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { /* The host needs data in the specified format. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA u32Formats=%x\n", u32Formats)); BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA); msg.AddInt32("Formats", (uint32)u32Formats); Looper()->PostMessage(&msg, this); break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { /* The host is terminating. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n")); fExiting = true; return VERR_INTERRUPTED; } default: Log(("VBoxClipboardService::%s: Unsupported message from host! Message = %u\n", __FUNCTION__, u32Msg)); } } else fExiting = true; LogRelFlow(("processed host event rc = %d\n", rc)); if (fExiting) break; } return 0; }
/** * Transfer clipboard data from the guest to the host. * * @returns VBox result code * @param u32Format The format of the data being sent * @param pv Pointer to the data being sent * @param cb Size of the data being sent in bytes */ static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb) { int rc; LogRelFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb)); rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb); LogRelFlowFunc(("rc=%Rrc\n", rc)); return rc; }
/** Stops the service. */ void SeamlessMain::stop() { LogRelFlowFunc(("\n")); VbglR3SeamlessSetCap(false); VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST); stopX11MonitorThread(); mX11Monitor.uninit(); LogRelFlowFunc(("returning\n")); }
/** * @thread EMT */ int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort) { int rc; LogRelFlowFunc(("fEnable = %d\n", fEnable)); rc = i_videoAccelEnable(fEnable, pVbvaMemory, pUpPort); LogRelFlowFunc(("%Rrc.\n", rc)); return rc; }
/** * Update the set of visible rectangles in the host. */ static void sendRegionUpdate(RTRECT *pRects, size_t cRects) { LogRelFlowFunc(("\n")); if (cRects && !pRects) /* Assertion */ { LogRelFunc(("ERROR: called with null pointer!\n")); return; } VbglR3SeamlessSendRects(cRects, pRects); LogRelFlowFunc(("returning\n")); }
void cleanupDisplay(void) { uint32_t fMouseFeatures = 0; LogRelFlowFunc(("\n")); VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED); int rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL); if (RT_SUCCESS(rc)) VbglR3SetMouseStatus( fMouseFeatures | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR); LogRelFlowFunc(("returning\n")); }
/* * Converts clipboard data from CF_HTML format to mimie clipboard format * Returns allocated buffer that contains html converted to text/html mime type * return result code * parameters - output buffer and size of output buffer * It allocates the buffer needed for storing converted fragment * Allocated buffer should be destroyed by RTMemFree after usage */ int ConvertCFHtmlToMime(const char *pcszSource, const uint32_t cch, char **ppszOutput, size_t *pcCh) { char* result = NULL; Assert(pcszSource); Assert(cch); Assert(ppszOutput); Assert(pcCh); size_t cStartOffset, cEndOffset; int rc = GetHeaderValue(pcszSource, "StartFragment:", &cStartOffset); if (!RT_SUCCESS(rc)) { LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected StartFragment. rc = %Rrc.\n", rc)); return VERR_INVALID_PARAMETER; } rc = GetHeaderValue(pcszSource, "EndFragment:", &cEndOffset); if (!RT_SUCCESS(rc)) { LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc.\n", rc)); return VERR_INVALID_PARAMETER; } if (cStartOffset > 0 && cEndOffset > 0 && cEndOffset > cStartOffset) { size_t cSubstrlen = cEndOffset - cStartOffset; result = (char*)RTMemAlloc(cSubstrlen + 1); if (result) { RT_BZERO(result, cSubstrlen + 1); rc = RTStrCopyEx(result, cSubstrlen + 1, pcszSource + cStartOffset, cSubstrlen); if (RT_SUCCESS(rc)) { *ppszOutput = result; *pcCh = cSubstrlen + 1; } else { LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment. rc = %Rrc\n", rc)); return rc; } } else { LogRelFlowFunc(("Error: Unknown CF_HTML format. Expected EndFragment.\n")); return VERR_NO_MEMORY; } } return VINF_SUCCESS; }
/** * Send an SCSI INQUIRY command to a device and return selected information. * @returns iprt status code * @returns VERR_TRY_AGAIN if the query failed but might succeed next time * @param pcszNode the full path to the device node * @param pu8Type where to store the SCSI device type on success (optional) * @param pchVendor where to store the vendor id string on success (optional) * @param cchVendor the size of the @a pchVendor buffer * @param pchModel where to store the product id string on success (optional) * @param cchModel the size of the @a pchModel buffer * @note check documentation on the SCSI INQUIRY command and the Linux kernel * SCSI headers included above if you want to understand what is going * on in this method. */ static int cdromDoInquiry(const char *pcszNode, uint8_t *pu8Type, char *pchVendor, size_t cchVendor, char *pchModel, size_t cchModel) { LogRelFlowFunc(("pcszNode=%s, pu8Type=%p, pchVendor=%p, cchVendor=%llu, pchModel=%p, cchModel=%llu\n", pcszNode, pu8Type, pchVendor, cchVendor, pchModel, cchModel)); AssertPtrReturn(pcszNode, VERR_INVALID_POINTER); AssertPtrNullReturn(pu8Type, VERR_INVALID_POINTER); AssertPtrNullReturn(pchVendor, VERR_INVALID_POINTER); AssertPtrNullReturn(pchModel, VERR_INVALID_POINTER); RTFILE hFile; int rc = RTFileOpen(&hFile, pcszNode, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK); if (RT_SUCCESS(rc)) { int rcIoCtl = 0; unsigned char u8Response[96] = { 0 }; struct cdrom_generic_command CdromCommandReq; RT_ZERO(CdromCommandReq); CdromCommandReq.cmd[0] = INQUIRY; CdromCommandReq.cmd[4] = sizeof(u8Response); CdromCommandReq.buffer = u8Response; CdromCommandReq.buflen = sizeof(u8Response); CdromCommandReq.data_direction = CGC_DATA_READ; CdromCommandReq.timeout = 5000; /* ms */ rc = RTFileIoCtl(hFile, CDROM_SEND_PACKET, &CdromCommandReq, 0, &rcIoCtl); if (RT_SUCCESS(rc) && rcIoCtl < 0) rc = RTErrConvertFromErrno(-CdromCommandReq.stat); RTFileClose(hFile); if (RT_SUCCESS(rc)) { if (pu8Type) *pu8Type = u8Response[0] & 0x1f; if (pchVendor) RTStrPrintf(pchVendor, cchVendor, "%.8s", &u8Response[8] /* vendor id string */); if (pchModel) RTStrPrintf(pchModel, cchModel, "%.16s", &u8Response[16] /* product id string */); LogRelFlowFunc(("returning success: type=%u, vendor=%.8s, product=%.16s\n", u8Response[0] & 0x1f, &u8Response[8], &u8Response[16])); return VINF_SUCCESS; } } LogRelFlowFunc(("returning %Rrc\n", rc)); return rc; }
/** * Add a byte to a queue. * * @param pQ Pointer to the queue. * @param val The byte to store. */ static void ps2kInsertQueue(GeneriQ *pQ, uint8_t val) { /* Check if queue is full. */ if (pQ->cUsed >= pQ->cSize) { LogRelFlowFunc(("queue %p full (%d entries)\n", pQ, pQ->cUsed)); return; } /* Insert data and update circular buffer write position. */ pQ->abQueue[pQ->wpos] = val; if (++pQ->wpos == pQ->cSize) pQ->wpos = 0; /* Roll over. */ ++pQ->cUsed; LogRelFlowFunc(("inserted 0x%02X into queue %p\n", val, pQ)); }
static DECLCALLBACK(int) svcRegisterExtension(void *, PFNHGCMSVCEXT pfnExtension, void *pvExtension) { LogRelFlowFunc(("pfnExtension = %p\n", pfnExtension)); VBOXCLIPBOARDEXTPARMS parms; if (pfnExtension) { /* Install extension. */ g_pfnExtension = pfnExtension; g_pvExtension = pvExtension; parms.u.pfnCallback = extCallback; g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms)); } else { if (g_pfnExtension) { parms.u.pfnCallback = NULL; g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms)); } /* Uninstall extension. */ g_pfnExtension = NULL; g_pvExtension = NULL; } return VINF_SUCCESS; }
/** * initialise the service. */ int SeamlessMain::init(void) { int rc; const char *pcszStage; LogRelFlowFunc(("\n")); do { pcszStage = "Connecting to the X server"; rc = mX11Monitor.init(sendRegionUpdate); if (RT_FAILURE(rc)) break; pcszStage = "Setting guest IRQ filter mask"; rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0); if (RT_FAILURE(rc)) break; pcszStage = "Reporting support for seamless capability"; rc = VbglR3SeamlessSetCap(true); if (RT_FAILURE(rc)) break; rc = startX11MonitorThread(); if (RT_FAILURE(rc)) break; } while(0); if (RT_FAILURE(rc)) VBClFatalError(("VBoxClient (seamless): failed to start. Stage: \"%s\" Error: %Rrc\n", pcszStage, rc)); return rc; }
/** * Get clipboard data from the host. * * @returns VBox result code * @param u32Format The format of the data being requested * @retval ppv On success and if pcb > 0, this will point to a buffer * to be freed with RTMemFree containing the data read. * @retval pcb On success, this contains the number of bytes of data * returned */ int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb) { int rc = VINF_SUCCESS; uint32_t cb = 1024; void *pv = RTMemAlloc(cb); *ppv = 0; LogRelFlowFunc(("u32Format=%u\n", u32Format)); if (RT_UNLIKELY(!pv)) rc = VERR_NO_MEMORY; if (RT_SUCCESS(rc)) rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) *ppv = pv; /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a * larger buffer. The size of the buffer needed is placed in *pcb. * So we start all over again. */ if (rc == VINF_BUFFER_OVERFLOW) { cb = *pcb; RTMemFree(pv); pv = RTMemAlloc(cb); if (RT_UNLIKELY(!pv)) rc = VERR_NO_MEMORY; if (RT_SUCCESS(rc)) rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) *ppv = pv; } /* Catch other errors. This also catches the case in which the buffer was * too small a second time, possibly because the clipboard contents * changed half-way through the operation. Since we can't say whether or * not this is actually an error, we just return size 0. */ if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc)) { *pcb = 0; if (pv != NULL) RTMemFree(pv); } LogRelFlowFunc(("returning %Rrc\n", rc)); if (RT_SUCCESS(rc)) LogRelFlow((" *pcb=%d\n", *pcb)); return rc; }
SeamlessMain::SeamlessMain(void) { LogRelFlowFunc(("\n")); mX11MonitorThread = NIL_RTTHREAD; mX11MonitorThreadStopping = false; mMode = VMMDev_Seamless_Disabled; mfPaused = true; }
/** * Reset all standard termination signals to call our signal handler, which * cleans up and exits. */ void vboxClientSetSignalHandlers(void) { struct sigaction sigAction; LogRelFlowFunc(("\n")); sigAction.sa_handler = vboxClientSignalHandler; sigemptyset(&sigAction.sa_mask); sigAction.sa_flags = 0; sigaction(SIGHUP, &sigAction, NULL); sigaction(SIGINT, &sigAction, NULL); sigaction(SIGQUIT, &sigAction, NULL); sigaction(SIGPIPE, &sigAction, NULL); sigaction(SIGALRM, &sigAction, NULL); sigaction(SIGTERM, &sigAction, NULL); sigaction(SIGUSR1, &sigAction, NULL); sigaction(SIGUSR2, &sigAction, NULL); LogRelFlowFunc(("returning\n")); }
/** * Waits for a seamless state change events from the host and dispatch it. * * @returns IRPT return code. */ int SeamlessMain::nextStateChangeEvent(void) { VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled; LogRelFlowFunc(("\n")); int rc = VbglR3SeamlessWaitEvent(&newMode); if (RT_SUCCESS(rc)) { mMode = newMode; switch (newMode) { case VMMDev_Seamless_Visible_Region: /* A simplified seamless mode, obtained by making the host VM window * borderless and making the guest desktop transparent. */ LogRelFlowFunc(("\"Visible region\" mode requested (VBoxClient).\n")); break; case VMMDev_Seamless_Disabled: LogRelFlowFunc(("\"Disabled\" mode requested (VBoxClient).\n")); break; case VMMDev_Seamless_Host_Window: /* One host window represents one guest window. Not yet implemented. */ LogRelFunc(("Unsupported \"host window\" mode requested (VBoxClient).\n")); return VERR_NOT_SUPPORTED; default: LogRelFunc(("Unsupported mode %d requested (VBoxClient).\n", newMode)); return VERR_NOT_SUPPORTED; } } if (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN) { if (mMode == VMMDev_Seamless_Visible_Region) mfPaused = false; else mfPaused = true; mX11Monitor.interruptEventWait(); } else { LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc)); } LogRelFlowFunc(("returning %Rrc\n", rc)); return rc; }
/** * This method first resets the current resolution using RandR to wake up * the graphics driver, then sets the resolution requested if it is among * those offered by the driver. */ static void setSize(Display *pDisplay, uint32_t cx, uint32_t cy) { XRRScreenConfiguration *pConfig; XRRScreenSize *pSizes; int cSizes; pConfig = XRRGetScreenInfo(pDisplay, DefaultRootWindow(pDisplay)); /* Reset the current mode */ LogRelFlowFunc(("Setting size %ux%u\n", cx, cy)); if (pConfig) { pSizes = XRRConfigSizes(pConfig, &cSizes); unsigned uDist = UINT32_MAX; int iMode = -1; for (int i = 0; i < cSizes; ++i) { #define VBCL_SQUARE(x) (x) * (x) unsigned uThisDist = VBCL_SQUARE(pSizes[i].width - cx) + VBCL_SQUARE(pSizes[i].height - cy); LogRelFlowFunc(("Found size %dx%d, distance %u\n", pSizes[i].width, pSizes[i].height, uThisDist)); #undef VBCL_SQUARE if (uThisDist < uDist) { uDist = uThisDist; iMode = i; } } if (iMode >= 0) { Time config_timestamp = 0; XRRConfigTimes(pConfig, &config_timestamp); LogRelFlowFunc(("Setting new size %d\n", iMode)); XRRSetScreenConfig(pDisplay, pConfig, DefaultRootWindow(pDisplay), iMode, RR_Rotate_0, config_timestamp); } XRRFreeScreenConfigInfo(pConfig); } }
/** * The actual X11 window configuration change monitor thread function. */ int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser) { RT_NOREF1(hThreadSelf); SeamlessMain *pHost = (SeamlessMain *)pvUser; int rc = VINF_SUCCESS; LogRelFlowFunc(("\n")); while (!pHost->mX11MonitorThreadStopping) { if (!pHost->mfPaused) { rc = pHost->mX11Monitor.start(); if (RT_FAILURE(rc)) VBClFatalError(("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n", pHost->mfPaused, rc)); } pHost->mX11Monitor.nextConfigurationEvent(); if (pHost->mfPaused || pHost->mX11MonitorThreadStopping) pHost->mX11Monitor.stop(); } LogRelFlowFunc(("returning %Rrc\n", rc)); return rc; }
/** * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent} */ static DECLCALLBACK(int) ps2mPutEvent(PPDMIMOUSEPORT pInterface, int32_t dx, int32_t dy, int32_t dz, int32_t dw, uint32_t fButtons) { PPS2M pThis = RT_FROM_MEMBER(pInterface, PS2M, Mouse.IPort); int rc = PDMCritSectEnter(pThis->pCritSectR3, VERR_SEM_BUSY); AssertReleaseRC(rc); LogRelFlowFunc(("dX=%d dY=%d dZ=%d dW=%d buttons=%02X\n", dx, dy, dz, dw, fButtons)); /* NB: The PS/2 Y axis direction is inverted relative to ours. */ ps2mPutEventWorker(pThis, dx, -dy, dz, dw, fButtons); PDMCritSectLeave(pThis->pCritSectR3); return VINF_SUCCESS; }
static int initDisplay(Display *pDisplay) { int rc = VINF_SUCCESS; uint32_t fMouseFeatures = 0; LogRelFlowFunc(("testing dynamic resizing\n")); int iDummy; if (!XRRQueryExtension(pDisplay, &iDummy, &iDummy)) rc = VERR_NOT_SUPPORTED; if (RT_SUCCESS(rc)) rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0); else VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST); /* Log and ignore the return value, as there is not much we can do with * it. */ LogRelFlowFunc(("dynamic resizing: result %Rrc\n", rc)); /* Enable support for switching between hardware and software cursors */ LogRelFlowFunc(("enabling relative mouse re-capturing support\n")); rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL); if (RT_SUCCESS(rc)) { rc = VbglR3CtlFilterMask(VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED, 0); if (RT_SUCCESS(rc)) rc = VbglR3SetMouseStatus ( fMouseFeatures & ~VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR); } if (RT_FAILURE(rc)) { VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED); VbglR3SetMouseStatus( fMouseFeatures | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR); } LogRelFlowFunc(("mouse re-capturing support: result %Rrc\n", rc)); return VINF_SUCCESS; }
extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable) { int rc = VINF_SUCCESS; LogRelFlowFunc(("ptable = %p\n", ptable)); if (!ptable) { rc = VERR_INVALID_PARAMETER; } else { LogRel2(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version)); if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) || ptable->u32Version != VBOX_HGCM_SVC_VERSION) { rc = VERR_INVALID_PARAMETER; } else { g_pHelpers = ptable->pHelpers; ptable->cbClient = sizeof (VBOXCLIPBOARDCLIENTDATA); ptable->pfnUnload = svcUnload; ptable->pfnConnect = svcConnect; ptable->pfnDisconnect = svcDisconnect; ptable->pfnCall = svcCall; ptable->pfnHostCall = svcHostCall; ptable->pfnSaveState = svcSaveState; ptable->pfnLoadState = svcLoadState; ptable->pfnRegisterExtension = svcRegisterExtension; ptable->pvService = NULL; /* Service specific initialization. */ rc = svcInit (); } } return rc; }
/** * Run the main service thread which listens for host state change * notifications. * @returns iprt status value. Service will be set to the stopped state on * failure. */ int SeamlessMain::run(void) { int rc = VINF_SUCCESS; LogRelFlowFunc(("\n")); /* This will only exit if something goes wrong. */ while (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED) { if (RT_FAILURE(rc)) /* If we are not stopping, sleep for a bit to avoid using up too much CPU while retrying. */ RTThreadYield(); rc = nextStateChangeEvent(); } if (RT_FAILURE(rc)) { LogRel(("VBoxClient (seamless): event loop failed with error: %Rrc\n", rc)); stop(); } return rc; }
/* For contiguous chunks just return the address in the buffer. * For crossing boundary - allocate a buffer from heap. */ static bool i_vbvaFetchCmd(VIDEOACCEL *pVideoAccel, VBVACMDHDR **ppHdr, uint32_t *pcbCmd) { VBVAMEMORY *pVbvaMemory = pVideoAccel->pVbvaMemory; uint32_t indexRecordFirst = pVbvaMemory->indexRecordFirst; uint32_t indexRecordFree = pVbvaMemory->indexRecordFree; #ifdef DEBUG_sunlover LogFlowFunc(("first = %d, free = %d\n", indexRecordFirst, indexRecordFree)); #endif /* DEBUG_sunlover */ if (!i_vbvaVerifyRingBuffer(pVbvaMemory)) { return false; } if (indexRecordFirst == indexRecordFree) { /* No records to process. Return without assigning output variables. */ return true; } uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVbvaMemory->aRecords[indexRecordFirst].cbRecord); #ifdef DEBUG_sunlover LogFlowFunc(("cbRecord = 0x%08X\n", cbRecordCurrent)); #endif /* DEBUG_sunlover */ uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL; if (pVideoAccel->cbVbvaPartial) { /* There is a partial read in process. Continue with it. */ Assert(pVideoAccel->pu8VbvaPartial); LogFlowFunc(("continue partial record cbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n", pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree)); if (cbRecord > pVideoAccel->cbVbvaPartial) { /* New data has been added to the record. */ if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory)) { return false; } } if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL)) { /* The record is completed by guest. Return it to the caller. */ *ppHdr = (VBVACMDHDR *)pVideoAccel->pu8VbvaPartial; *pcbCmd = pVideoAccel->cbVbvaPartial; pVideoAccel->pu8VbvaPartial = NULL; pVideoAccel->cbVbvaPartial = 0; /* Advance the record index. */ pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover LogFlowFunc(("partial done ok, data = %d, free = %d\n", pVbvaMemory->off32Data, pVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ } return true; } /* A new record need to be processed. */ if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL) { /* Current record is being written by guest. '=' is important here. */ if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD) { /* Partial read must be started. */ if (!i_vbvaPartialRead(&pVideoAccel->pu8VbvaPartial, &pVideoAccel->cbVbvaPartial, cbRecord, pVbvaMemory)) { return false; } LogFlowFunc(("started partial record cbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n", pVideoAccel->cbVbvaPartial, cbRecordCurrent, indexRecordFirst, indexRecordFree)); } return true; } /* Current record is complete. If it is not empty, process it. */ if (cbRecord) { /* The size of largest contiguous chunk in the ring biffer. */ uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data; /* The ring buffer pointer. */ uint8_t *au8RingBuffer = &pVbvaMemory->au8RingBuffer[0]; /* The pointer to data in the ring buffer. */ uint8_t *src = &au8RingBuffer[pVbvaMemory->off32Data]; /* Fetch or point the data. */ if (u32BytesTillBoundary >= cbRecord) { /* The command does not cross buffer boundary. Return address in the buffer. */ *ppHdr = (VBVACMDHDR *)src; /* Advance data offset. */ pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; } else { /* The command crosses buffer boundary. Rare case, so not optimized. */ uint8_t *dst = (uint8_t *)RTMemAlloc(cbRecord); if (!dst) { LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord)); pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE; return false; } i_vbvaFetchBytes(pVbvaMemory, dst, cbRecord); *ppHdr = (VBVACMDHDR *)dst; #ifdef DEBUG_sunlover LogFlowFunc(("Allocated from heap %p\n", dst)); #endif /* DEBUG_sunlover */ } } *pcbCmd = cbRecord; /* Advance the record index. */ pVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS; #ifdef DEBUG_sunlover LogFlowFunc(("done ok, data = %d, free = %d\n", pVbvaMemory->off32Data, pVbvaMemory->off32Free)); #endif /* DEBUG_sunlover */ return true; }
int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory, PPDMIDISPLAYPORT pUpPort) { int rc = VINF_SUCCESS; VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy; /* Called each time the guest wants to use acceleration, * or when the VGA device disables acceleration, * or when restoring the saved state with accel enabled. * * VGA device disables acceleration on each video mode change * and on reset. * * Guest enabled acceleration at will. And it has to enable * acceleration after a mode change. */ LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n", pVideoAccel->fVideoAccelEnabled, fEnable, pVbvaMemory)); /* Strictly check parameters. Callers must not pass anything in the case. */ Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL)); if (!i_VideoAccelAllowed ()) return VERR_NOT_SUPPORTED; /* Check that current status is not being changed */ if (pVideoAccel->fVideoAccelEnabled == fEnable) return rc; if (pVideoAccel->fVideoAccelEnabled) { /* Process any pending orders and empty the VBVA ring buffer. */ i_videoAccelFlush (pUpPort); } if (!fEnable && pVideoAccel->pVbvaMemory) pVideoAccel->pVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED; if (fEnable) { /* Process any pending VGA device changes, resize. */ pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false); } /* Protect the videoaccel state transition. */ RTCritSectEnter(&mVideoAccelLock); if (fEnable) { /* Initialize the hardware memory. */ i_vbvaSetMemoryFlags(pVbvaMemory, true, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors); pVbvaMemory->off32Data = 0; pVbvaMemory->off32Free = 0; memset(pVbvaMemory->aRecords, 0, sizeof(pVbvaMemory->aRecords)); pVbvaMemory->indexRecordFirst = 0; pVbvaMemory->indexRecordFree = 0; pVideoAccel->pVbvaMemory = pVbvaMemory; pVideoAccel->fVideoAccelEnabled = true; LogRel(("VBVA: Enabled.\n")); } else { pVideoAccel->pVbvaMemory = NULL; pVideoAccel->fVideoAccelEnabled = false; LogRel(("VBVA: Disabled.\n")); } RTCritSectLeave(&mVideoAccelLock); if (!fEnable) { pUpPort->pfnUpdateDisplayAll(pUpPort, /* fFailOnResize = */ false); } /* Notify the VMMDev, which saves VBVA status in the saved state, * and needs to know current status. */ VMMDev *pVMMDev = mParent->i_getVMMDev(); if (pVMMDev) { PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); if (pVMMDevPort) pVMMDevPort->pfnVBVAChange(pVMMDevPort, fEnable); } LogRelFlowFunc(("%Rrc.\n", rc)); return rc; }
/** * Display change request monitor thread function. * Before entering the loop, we re-read the last request * received, and if the first one received inside the * loop is identical we ignore it, because it is probably * stale. */ static int runDisplay(Display *pDisplay) { LogRelFlowFunc(("\n")); Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch); Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr); int RRMaj, RRMin; if (!XRRQueryVersion(pDisplay, &RRMaj, &RRMin)) RRMin = 0; const char *pcszXrandr = "xrandr"; if (RTFileExists("/usr/X11/bin/xrandr")) pcszXrandr = "/usr/X11/bin/xrandr"; int rc = RTThreadCreate(NULL, x11ConnectionMonitor, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "X11 monitor"); if (RT_FAILURE(rc)) return rc; while (true) { uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0; rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED, RT_INDEFINITE_WAIT, &fEvents); if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED) /* VERR_NO_MEMORY? */ return rc; /* Jiggle the mouse pointer to wake up the driver. */ XGrabPointer(pDisplay, DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, GrabModeAsync, None, hClockCursor, CurrentTime); XFlush(pDisplay); XGrabPointer(pDisplay, DefaultRootWindow(pDisplay), true, 0, GrabModeAsync, GrabModeAsync, None, hArrowCursor, CurrentTime); XFlush(pDisplay); XUngrabPointer(pDisplay, CurrentTime); XFlush(pDisplay); /* And if it is a size hint, set the new size now that the video * driver has had a chance to update its list. */ if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)) { int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay, true); /* If we are not stopping, sleep for a bit to avoid using up too much CPU while retrying. */ if (RT_FAILURE(rc2)) RTThreadYield(); else if (RRMin < 2) setSize(pDisplay, cx, cy); else { char szCommand[256]; RTStrPrintf(szCommand, sizeof(szCommand), "%s --output VBOX%u --set VBOX_MODE %dx%d", pcszXrandr, iDisplay, cx, cy); system(szCommand); RTStrPrintf(szCommand, sizeof(szCommand), "%s --output VBOX%u --preferred", pcszXrandr, iDisplay); system(szCommand); } } } LogRelFlowFunc(("returning VINF_SUCCESS\n")); return VINF_SUCCESS; }
static int showNotify(const char *pcHeader, const char *pcBody) { int rc; # ifdef VBOX_WITH_DBUS DBusConnection *conn; DBusMessage* msg = NULL; conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); if (conn == NULL) { LogRelFlowFunc(("Could not retrieve D-BUS session bus!\n")); rc = VERR_INVALID_HANDLE; } else { msg = dbus_message_new_method_call("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify"); if (msg == NULL) { LogRel(("Could not create D-BUS message!\n")); rc = VERR_INVALID_HANDLE; } else rc = VINF_SUCCESS; } if (RT_SUCCESS(rc)) { uint32_t msg_replace_id = 0; const char *msg_app = "VBoxClient"; const char *msg_icon = ""; const char *msg_summary = pcHeader; const char *msg_body = pcBody; int32_t msg_timeout = -1; /* Let the notification server decide */ DBusMessageIter iter; DBusMessageIter array; DBusMessageIter dict; DBusMessageIter value; DBusMessageIter variant; DBusMessageIter data; /* Format: UINT32 org.freedesktop.Notifications.Notify * (STRING app_name, UINT32 replaces_id, STRING app_icon, STRING summary, STRING body, * ARRAY actions, DICT hints, INT32 expire_timeout) */ dbus_message_iter_init_append(msg,&iter); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_app); dbus_message_iter_append_basic(&iter,DBUS_TYPE_UINT32,&msg_replace_id); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_icon); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_summary); dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&msg_body); dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array); dbus_message_iter_close_container(&iter,&array); dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,"{sv}",&array); dbus_message_iter_close_container(&iter,&array); dbus_message_iter_append_basic(&iter,DBUS_TYPE_INT32,&msg_timeout); DBusError err; dbus_error_init(&err); DBusMessage *reply; reply = dbus_connection_send_with_reply_and_block(conn, msg, 30 * 1000 /* 30 seconds timeout */, &err); if (dbus_error_is_set(&err)) { LogRel(("D-BUS returned an error while sending the notification: %s", err.message)); } else if (reply) { dbus_connection_flush(conn); dbus_message_unref(reply); } if (dbus_error_is_set(&err)) dbus_error_free(&err); } if (msg != NULL) dbus_message_unref(msg); # else /* TODO: Implement me */ rc = VINF_SUCCESS; # endif /* VBOX_WITH_DBUS */ return rc; }
SeamlessMain::~SeamlessMain() { LogRelFlowFunc(("\n")); stop(); }
/** * The main loop of our clipboard reader. */ int vboxClipboardMain(void) { int rc; LogRelFlowFunc(("Starting guest clipboard service\n")); bool fExiting = false; while (!fExiting) { uint32_t Msg; uint32_t fFormats; rc = VbglR3ClipboardGetHostMsg(g_ctx.client, &Msg, &fFormats); if (RT_SUCCESS(rc)) { switch (Msg) { case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS: { /* The host has announced available clipboard formats. * Save the information so that it is available for * future requests from guest applications. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS fFormats=%x\n", fFormats)); ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats); break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { /* The host needs data in the specified format. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA fFormats=%x\n", fFormats)); CLIPREADCBREQ *pReq; pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(*pReq)); if (!pReq) { rc = VERR_NO_MEMORY; fExiting = true; } else { pReq->u32Format = fFormats; ClipRequestDataFromX11(g_ctx.pBackend, fFormats, pReq); } break; } case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { /* The host is terminating. */ LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n")); if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend))) ClipDestructX11(g_ctx.pBackend); fExiting = true; break; } default: LogRel2(("Unsupported message from host!!!\n")); } } LogRelFlow(("processed host event rc = %d\n", rc)); } LogRelFlowFunc(("rc=%d\n", rc)); return rc; }
int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual) { LogFlow(("vboxClipboardReadData: u32Format = %02X\n", u32Format)); HANDLE hClip = NULL; /* * The guest wants to read data in the given format. */ int rc = vboxOpenClipboard(pClient->pCtx->hwnd); if (RT_SUCCESS(rc)) { dprintf(("Clipboard opened.\n")); if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData (CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock (hClip); if (lp != NULL) { dprintf(("CF_DIB\n")); vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize (hClip), pv, cb, pcbActual); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock (hClip); if (uniString != NULL) { dprintf(("CF_UNICODETEXT\n")); vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW (uniString) + 1) * 2, pv, cb, pcbActual); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); if (format != 0) { hClip = GetClipboardData (format); if (hClip != NULL) { LPVOID lp = GlobalLock (hClip); if (lp != NULL) { dprintf(("CF_HTML\n")); vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize (hClip), pv, cb, pcbActual); LogRelFlowFunc(("Raw HTML clipboard data from host :")); DumpHtml((char*)pv, cb); GlobalUnlock(hClip); } else { hClip = NULL; } } } } CloseClipboard (); } else { dprintf(("vboxClipboardReadData: failed to open clipboard, rc: %Rrc\n", rc)); } if (hClip == NULL) { /* Reply with empty data. */ vboxClipboardGetData (0, NULL, 0, pv, cb, pcbActual); } return VINF_SUCCESS; }