/* $Id: display_window.cpp $ */ /** @file * Presenter API: CrFbDisplayWindow class implementation -- display content into host GUI window. */ /* * Copyright (C) 2014-2019 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "server_presenter.h" CrFbDisplayWindow::CrFbDisplayWindow(const RTRECT *pViewportRect, uint64_t parentId) : mpWindow(NULL), mViewportRect(*pViewportRect), mu32Screen(~0), mParentId(parentId) { mFlags.u32Value = 0; } CrFbDisplayWindow::~CrFbDisplayWindow() { if (mpWindow) delete mpWindow; } int CrFbDisplayWindow::UpdateBegin(struct CR_FRAMEBUFFER *pFb) { int rc = mpWindow ? mpWindow->UpdateBegin() : VINF_SUCCESS; if (RT_SUCCESS(rc)) { rc = CrFbDisplayBase::UpdateBegin(pFb); if (RT_SUCCESS(rc)) return VINF_SUCCESS; else { WARN(("err")); if (mpWindow) mpWindow->UpdateEnd(); } } else WARN(("err")); return rc; } void CrFbDisplayWindow::UpdateEnd(struct CR_FRAMEBUFFER *pFb) { CrFbDisplayBase::UpdateEnd(pFb); if (mpWindow) mpWindow->UpdateEnd(); } int CrFbDisplayWindow::RegionsChanged(struct CR_FRAMEBUFFER *pFb) { int rc = CrFbDisplayBase::RegionsChanged(pFb); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } if (mpWindow && mpWindow->GetParentId()) { rc = mpWindow->Create(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } return VINF_SUCCESS; } int CrFbDisplayWindow::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } if (mpWindow && mpWindow->GetParentId()) { rc = mpWindow->Create(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } return VINF_SUCCESS; } int CrFbDisplayWindow::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) { int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } if (mpWindow && mpWindow->GetParentId()) { rc = mpWindow->Create(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } return VINF_SUCCESS; } int CrFbDisplayWindow::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) { int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } if (mpWindow && mpWindow->GetParentId()) { rc = mpWindow->Create(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } return VINF_SUCCESS; } int CrFbDisplayWindow::FramebufferChanged(struct CR_FRAMEBUFFER *pFb) { int rc = CrFbDisplayBase::FramebufferChanged(pFb); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } return screenChanged(); } const RTRECT* CrFbDisplayWindow::getViewportRect() { return &mViewportRect; } int CrFbDisplayWindow::setViewportRect(const RTRECT *pViewportRect) { if (!isUpdating()) { WARN(("not updating!")); return VERR_INVALID_STATE; } // always call SetPosition to ensure window is adjustep properly // if (pViewportRect->xLeft != mViewportRect.xLeft || pViewportRect->yTop != mViewportRect.yTop) if (mpWindow) { const RTRECT* pRect = getRect(); int rc = mpWindow->SetPosition(pRect->xLeft - pViewportRect->xLeft, pRect->yTop - pViewportRect->yTop); if (!RT_SUCCESS(rc)) { WARN(("SetPosition failed")); return rc; } } mViewportRect = *pViewportRect; return VINF_SUCCESS; } CrFbWindow * CrFbDisplayWindow::windowDetach(bool fCleanup) { if (isUpdating()) { WARN(("updating!")); return NULL; } CrFbWindow * pWindow = mpWindow; if (mpWindow) { if (fCleanup) windowCleanup(); mpWindow = NULL; } return pWindow; } CrFbWindow * CrFbDisplayWindow::windowAttach(CrFbWindow * pNewWindow) { if (isUpdating()) { WARN(("updating!")); return NULL; } CrFbWindow * pOld = mpWindow; if (mpWindow) windowDetach(); mpWindow = pNewWindow; if (pNewWindow) windowSync(); return mpWindow; } int CrFbDisplayWindow::reparent(uint64_t parentId) { if (!isUpdating()) { WARN(("not updating!")); return VERR_INVALID_STATE; } crDebug("CrFbDisplayWindow: change parent from %p to %p.", mParentId, parentId); mParentId = parentId; int rc = VINF_SUCCESS; /* Force notify Render SPU about parent window ID change in order to prevent * crashes when it tries to access already deallocated parent window. * Previously, we also used isActive() here, however it might become FALSE for the case * when VM Window goes fullscreen mode and back. */ if ( /* isActive() && */ mpWindow) { rc = mpWindow->Reparent(parentId); if (!RT_SUCCESS(rc)) WARN(("window reparent failed")); mFlags.fNeForce = 1; } return rc; } bool CrFbDisplayWindow::isVisible() { HCR_FRAMEBUFFER hFb = getFramebuffer(); if (!hFb) return false; const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb); return !CrVrScrCompositorIsEmpty(pCompositor); } int CrFbDisplayWindow::winVisibilityChanged() { HCR_FRAMEBUFFER hFb = getFramebuffer(); if (!hFb || !CrFbIsEnabled(hFb)) { Assert(!mpWindow || !mpWindow->IsVisivle()); return VINF_SUCCESS; } int rc = VINF_SUCCESS; if (mpWindow) { rc = mpWindow->UpdateBegin(); if (RT_SUCCESS(rc)) { rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); if (!RT_SUCCESS(rc)) WARN(("SetVisible failed, rc %d", rc)); mpWindow->UpdateEnd(); } else WARN(("UpdateBegin failed, rc %d", rc)); } return rc; } CrFbWindow* CrFbDisplayWindow::getWindow() { return mpWindow; } void CrFbDisplayWindow::onUpdateEnd() { CrFbDisplayBase::onUpdateEnd(); bool fVisible = isVisible(); if (mFlags.fNeVisible != fVisible || mFlags.fNeForce) { crVBoxServerNotifyEvent(mu32Screen, fVisible? VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_VISIBLE: VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_HIDDEN, NULL, 0); mFlags.fNeVisible = fVisible; mFlags.fNeForce = 0; } } void CrFbDisplayWindow::ueRegions() { if (mpWindow) mpWindow->SetVisibleRegionsChanged(); } int CrFbDisplayWindow::screenChanged() { if (!isUpdating()) { WARN(("not updating!")); return VERR_INVALID_STATE; } int rc = windowDimensionsSync(); if (!RT_SUCCESS(rc)) { WARN(("windowDimensionsSync failed rc %d", rc)); return rc; } return VINF_SUCCESS; } int CrFbDisplayWindow::windowSetCompositor(bool fSet) { if (!mpWindow) return VINF_SUCCESS; if (fSet) { const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); return mpWindow->SetCompositor(pCompositor); } return mpWindow->SetCompositor(NULL); } int CrFbDisplayWindow::windowCleanup() { if (!mpWindow) return VINF_SUCCESS; int rc = mpWindow->UpdateBegin(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } rc = windowDimensionsSync(true); if (!RT_SUCCESS(rc)) { WARN(("err")); mpWindow->UpdateEnd(); return rc; } rc = windowSetCompositor(false); if (!RT_SUCCESS(rc)) { WARN(("err")); mpWindow->UpdateEnd(); return rc; } mpWindow->UpdateEnd(); return VINF_SUCCESS; } int CrFbDisplayWindow::fbCleanup() { int rc = windowCleanup(); if (!RT_SUCCESS(rc)) { WARN(("windowCleanup failed")); return rc; } return CrFbDisplayBase::fbCleanup(); } bool CrFbDisplayWindow::isActive() { HCR_FRAMEBUFFER hFb = getFramebuffer(); return hFb && CrFbIsEnabled(hFb); } int CrFbDisplayWindow::windowDimensionsSync(bool fForceCleanup) { int rc = VINF_SUCCESS; if (!mpWindow) return VINF_SUCCESS; //HCR_FRAMEBUFFER hFb = getFramebuffer(); if (!fForceCleanup && isActive()) { const RTRECT* pRect = getRect(); if (mpWindow->GetParentId() != mParentId) { rc = mpWindow->Reparent(mParentId); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } setRegionsChanged(); rc = mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } else { rc = mpWindow->SetVisible(false); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } #if 0 rc = mpWindow->Reparent(mDefaultParentId); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } #endif } return rc; } int CrFbDisplayWindow::windowSync() { if (!mpWindow) return VINF_SUCCESS; int rc = mpWindow->UpdateBegin(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } rc = windowSetCompositor(true); if (!RT_SUCCESS(rc)) { WARN(("err")); mpWindow->UpdateEnd(); return rc; } rc = windowDimensionsSync(); if (!RT_SUCCESS(rc)) { WARN(("err")); mpWindow->UpdateEnd(); return rc; } mpWindow->UpdateEnd(); return rc; } int CrFbDisplayWindow::fbSync() { int rc = CrFbDisplayBase::fbSync(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } HCR_FRAMEBUFFER hFb = getFramebuffer(); mu32Screen = CrFbGetScreenInfo(hFb)->u32ViewIndex; rc = windowSync(); if (!RT_SUCCESS(rc)) { WARN(("windowSync failed %d", rc)); return rc; } if (CrFbHas3DData(hFb)) { if (mpWindow && mpWindow->GetParentId()) { rc = mpWindow->Create(); if (!RT_SUCCESS(rc)) { WARN(("err")); return rc; } } } return VINF_SUCCESS; } const struct RTRECT* CrFbDisplayWindow::getRect() { const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); return CrVrScrCompositorRectGet(pCompositor); }