display_window.cpp revision 07c4af24c9b4431ab9a934079b348adbc66d6ff9
/* $Id$ */
/** @file
* Presenter API: CrFbDisplayWindow class implementation -- display content into host GUI window.
*/
/*
* Copyright (C) 2014 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)
{
crDebug("CrFbDisplayWindow: created with parentID %p.", 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;
}
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;
}
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;
}
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;
}
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;
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, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA, &fVisible, sizeof(fVisible));
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;
crDebug("CrFbDisplayWindow: sync window dimentions: fForceCleanup=%s, mpWindow=%p, isActive()=%s",
fForceCleanup ? "yes" : "no",
mpWindow,
isActive() ? "yes" : "no");
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;
}
return VINF_SUCCESS;
}
const struct RTRECT* CrFbDisplayWindow::getRect()
{
const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer());
return CrVrScrCompositorRectGet(pCompositor);
}