STDMETHODIMP UIFrameBuffer::SetVisibleRegion(BYTE *pRectangles, ULONG uCount) { LogRelFlow(("UIFrameBuffer::SetVisibleRegion: Rectangle count=%lu\n", (unsigned long)uCount)); /* Make sure frame-buffer is not yet scheduled for removal: */ if (m_fIsScheduledToDelete) return E_FAIL; /* Make sure rectangles were passed: */ PRTRECT rects = (PRTRECT)pRectangles; if (!rects) return E_POINTER; /* Compose region: */ QRegion region; for (ULONG ind = 0; ind < uCount; ++ind) { /* Get current rectangle: */ QRect rect; rect.setLeft(rects->xLeft); rect.setTop(rects->yTop); /* Which is inclusive: */ rect.setRight(rects->xRight - 1); rect.setBottom(rects->yBottom - 1); /* Append region: */ region += rect; ++rects; } /* See comment in setView(): */ lock(); /* We are directly updating synchronous visible-region: */ m_syncVisibleRegion = region; /* And send async signal to update asynchronous one: */ if (m_pMachineView) emit sigSetVisibleRegion(region); /* Unlock thread finally: */ unlock(); /* Confirm SetVisibleRegion: */ return S_OK; }
STDMETHODIMP UIFrameBufferQuartz2D::SetVisibleRegion(BYTE *pRectangles, ULONG aCount) { LogRel2(("UIFrameBufferQuartz2D::SetVisibleRegion: Rectangle count=%lu\n", (unsigned long)aCount)); /* Make sure rectangles were passed: */ if (!pRectangles) { LogRel2(("UIFrameBufferQuartz2D::SetVisibleRegion: Invalid pRectangles pointer!\n")); return E_POINTER; } /* Lock access to frame-buffer: */ lock(); /* Make sure frame-buffer is used: */ if (m_fIsMarkedAsUnused) { LogRel2(("UIFrameBufferQuartz2D::SetVisibleRegion: Ignored!\n")); /* Unlock access to frame-buffer: */ unlock(); /* Ignore SetVisibleRegion: */ return E_FAIL; } /** @todo r=bird: Is this thread safe? If I remember the code flow correctly, the * GUI thread could be happily jogging along paintEvent now on another cpu core. * This function is called on the EMT (emulation thread). Which means, blocking * execution waiting for a lock is out of the question. A quick solution using * ASMAtomic(Cmp)XchgPtr and a struct { cAllocated; cRects; aRects[1]; } * *mRegion, *mUnusedRegion; should suffice (and permit you to reuse allocations). */ RegionRects *rgnRcts = ASMAtomicXchgPtrT(&mRegionUnused, NULL, RegionRects *); if (rgnRcts && rgnRcts->allocated < aCount) { RTMemFree (rgnRcts); rgnRcts = NULL; } if (!rgnRcts) { ULONG allocated = RT_ALIGN_32(aCount + 1, 32); allocated = RT_MAX (128, allocated); rgnRcts = (RegionRects *)RTMemAlloc(RT_OFFSETOF(RegionRects, rcts[allocated])); if (!rgnRcts) { /* Unlock access to frame-buffer: */ unlock(); return E_OUTOFMEMORY; } rgnRcts->allocated = allocated; } rgnRcts->used = 0; /* Compose region: */ QRegion reg; PRTRECT rects = (PRTRECT)pRectangles; QRect vmScreenRect(0, 0, width(), height()); for (ULONG ind = 0; ind < aCount; ++ ind) { /* Get current rectangle: */ QRect rect; rect.setLeft(rects->xLeft); rect.setTop(rects->yTop); /* Which is inclusive: */ rect.setRight(rects->xRight - 1); rect.setBottom(rects->yBottom - 1); /* The rect should intersect with the vm screen. */ rect = vmScreenRect.intersect(rect); ++rects; /* Make sure only valid rects are distributed: */ if (rect.isValid() && rect.width() > 0 && rect.height() > 0) reg += rect; else continue; /* That is some *magic* added by Knut in r27807: */ CGRect *cgRct = &rgnRcts->rcts[rgnRcts->used]; cgRct->origin.x = rect.x(); cgRct->origin.y = height() - rect.y() - rect.height(); cgRct->size.width = rect.width(); cgRct->size.height = rect.height(); rgnRcts->used++; } RegionRects *pOld = ASMAtomicXchgPtrT(&mRegion, rgnRcts, RegionRects *); if ( pOld && !ASMAtomicCmpXchgPtr(&mRegionUnused, pOld, NULL)) RTMemFree(pOld); /* Send async signal to update asynchronous visible-region: */ LogRel2(("UIFrameBufferQuartz2D::SetVisibleRegion: Sending to async-handler...\n")); emit sigSetVisibleRegion(reg); /* Unlock access to frame-buffer: */ unlock(); /* Confirm SetVisibleRegion: */ return S_OK; }
if (m_pMachineView) prepareConnections(); /* Unlock thread finally: */ unlock(); } void UIFrameBuffer::prepareConnections() { connect(this, SIGNAL(sigRequestResize(int, uchar*, int, int, int, int)), m_pMachineView, SLOT(sltHandleRequestResize(int, uchar*, int, int, int, int)), Qt::QueuedConnection); connect(this, SIGNAL(sigNotifyUpdate(int, int, int, int)), m_pMachineView, SLOT(sltHandleNotifyUpdate(int, int, int, int)), Qt::QueuedConnection); connect(this, SIGNAL(sigSetVisibleRegion(QRegion)), m_pMachineView, SLOT(sltHandleSetVisibleRegion(QRegion)), Qt::QueuedConnection); connect(this, SIGNAL(sigNotifyAbout3DOverlayVisibilityChange(bool)), m_pMachineView, SLOT(sltHandle3DOverlayVisibilityChange(bool)), Qt::QueuedConnection); } void UIFrameBuffer::cleanupConnections() { disconnect(this, SIGNAL(sigRequestResize(int, uchar*, int, int, int, int)), m_pMachineView, SLOT(sltHandleRequestResize(int, uchar*, int, int, int, int))); disconnect(this, SIGNAL(sigNotifyUpdate(int, int, int, int)), m_pMachineView, SLOT(sltHandleNotifyUpdate(int, int, int, int))); disconnect(this, SIGNAL(sigSetVisibleRegion(QRegion)), m_pMachineView, SLOT(sltHandleSetVisibleRegion(QRegion)));