//************************************************************************
//  The Logitech LCD SDK, including all acompanying documentation,
//  is protected by intellectual property laws.  All use of the Logitech
//  LCD SDK is subject to the License Agreement found in the
//  "Logitech LCD SDK License Agreement" file and in the Reference Manual.  
//  All rights not expressly granted by Logitech are reserved.
//************************************************************************
 
//************************************************************************
//
// LCDOutput.cpp
//
// The CLCDOutput manages the actual device and the various pages that
// are sent to that device
// 
// This class is now managed by CLCDConnection. You no longer need to 
// derive or instantiate this class yourself
//
// Logitech LCD SDK
//
// Copyright 2010 Logitech Inc.
//************************************************************************
 
#include "LCDUI.h"
 
#pragma warning(disable:4995)
 
//************************************************************************
//
// CLCDOutput::CLCDOutput
//
//************************************************************************
 
CLCDOutput::CLCDOutput(void)
:   m_pActivePage(NULL),
    m_hDevice(LGLCD_INVALID_DEVICE),
    m_bSetAsForeground(FALSE),
    m_dwButtonState(0),
    m_nPriority(LGLCD_PRIORITY_NORMAL),
    m_pGfx(NULL)
{
    ZeroMemory(&m_OpenByTypeContext, sizeof(m_OpenByTypeContext));
}
 
 
//************************************************************************
//
// CLCDOutput::~CLCDOutput
//
//************************************************************************
 
CLCDOutput::~CLCDOutput(void)
{
    Shutdown();
}
 
 
//************************************************************************
//
// CLCDOutput::SetGfx
//
//************************************************************************
 
void CLCDOutput::SetGfx(CLCDGfxBase *gfx)
{
    m_pGfx = gfx;
}
 
 
//************************************************************************
//
// CLCDOutput::Open
//
//************************************************************************
 
BOOL CLCDOutput::Open(lgLcdOpenContext & OpenContext)
{
    //Close the old device if there is one
    Close();
 
    DWORD res = lgLcdOpen(&OpenContext);
    if (ERROR_SUCCESS != res)
    {
        if( res == ERROR_INVALID_PARAMETER )
        {
            LCDUITRACE( _T("Open failed: invalid parameter.\n") );
            return FALSE;
        }
        else if( res == ERROR_ALREADY_EXISTS )
        {
            LCDUITRACE( _T("Open failed: already exists.\n") );
            return FALSE;
        }
        return FALSE;
    }
 
    m_hDevice = OpenContext.device;
    m_dwButtonState = 0;
 
    // restores
    SetAsForeground(m_bSetAsForeground);
 
    OnOpenedDevice(m_hDevice);
 
    return TRUE;
}
 
 
//************************************************************************
//
// CLCDOutput::OpenByType
//
//************************************************************************
 
BOOL CLCDOutput::OpenByType(lgLcdOpenByTypeContext &OpenContext)
{
    //Close the old device if there is one
    Close();
 
    DWORD res = lgLcdOpenByType(&OpenContext);
    if (ERROR_SUCCESS != res)
    {
        if( res == ERROR_INVALID_PARAMETER )
        {
            LCDUITRACE( _T("Open failed: invalid parameter.\n") );
            return FALSE;
        }
        else if( res == ERROR_ALREADY_EXISTS )
        {
            LCDUITRACE( _T("Open failed: already exists.\n") );
            return FALSE;
        }
        return FALSE;
    }
 
    m_hDevice = OpenContext.device;
    m_dwButtonState = 0;
 
    // restores
    SetAsForeground(m_bSetAsForeground);
 
    m_OpenByTypeContext = OpenContext;
 
    OnOpenedDevice(m_hDevice);
 
    return TRUE;
}
 
 
//************************************************************************
//
// CLCDOutput::ReOpenDeviceType
//
//************************************************************************
 
BOOL CLCDOutput::ReOpenDeviceType(void)
{
    // The device type must be active
    if (!HasBeenOpenedByDeviceType())
    {
        return FALSE;
    }
 
    return OpenByType(m_OpenByTypeContext);
}
 
 
//************************************************************************
//
// CLCDOutput::Close
//
//************************************************************************
 
void CLCDOutput::Close(void)
{
    if( LGLCD_INVALID_DEVICE != m_hDevice )
    {
        OnClosingDevice(m_hDevice);
        lgLcdClose(m_hDevice);
        m_hDevice = LGLCD_INVALID_DEVICE;
    }
}
 
 
//************************************************************************
//
// CLCDOutput::Shutdown
//
//************************************************************************
 
void CLCDOutput::Shutdown(void)
{
    Close();
}
 
 
//************************************************************************
//
// CLCDOutput::AddPage
//
//************************************************************************
 
void CLCDOutput::AddPage(CLCDPage *pPage)
{
    pPage->Initialize();
    AddObject(pPage);
}
 
 
//************************************************************************
//
// CLCDOutput::RemovePage
//
//************************************************************************
 
void CLCDOutput::RemovePage(CLCDPage *pPage)
{
    RemoveObject(pPage);
}
 
 
//************************************************************************
//
// CLCDOutput::ShowPage
//
//************************************************************************
 
void CLCDOutput::ShowPage(CLCDPage *pPage, BOOL bShow)
{
    LCDUIASSERT(NULL != pPage);
 
    if (bShow)
    {
        m_pActivePage = pPage;
 
        OnPageShown(pPage);
    }
    else
    {
        // Expire it and update
        pPage->SetExpiration(0);
        OnUpdate(GetTickCount());
    }
}
 
 
//************************************************************************
//
// CLCDOutput::GetShowingPage
//
//************************************************************************
 
CLCDPage* CLCDOutput::GetShowingPage(void)
{
    return m_pActivePage;
}
 
 
//************************************************************************
//
// CLCDOutput::SetScreenPriority
//
//************************************************************************
 
void CLCDOutput::SetScreenPriority(DWORD priority)
{
    // Priority has changed
    // If we're going into idle, send an idle frame
    if (LGLCD_PRIORITY_IDLE_NO_SHOW == priority)
    {
        lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr,
            LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW));
    }
 
    m_nPriority = priority;
}
 
 
//************************************************************************
//
// CLCDOutput::GetScreenPriority
//
//************************************************************************
 
DWORD CLCDOutput::GetScreenPriority(void)
{
    return m_nPriority;
}
 
 
//************************************************************************
//
// CLCDOutput::IsOpened
//
//************************************************************************
 
BOOL CLCDOutput::IsOpened(void)
{
    return (LGLCD_INVALID_DEVICE != m_hDevice);
}
 
 
//************************************************************************
//
// CLCDOutput::SetAsForeground
//
//************************************************************************
 
HRESULT CLCDOutput::SetAsForeground(BOOL bSetAsForeground)
{
    m_bSetAsForeground = bSetAsForeground;
    if (LGLCD_INVALID_DEVICE != m_hDevice)
    {
        DWORD dwRes = lgLcdSetAsLCDForegroundApp(m_hDevice, bSetAsForeground);
        if(ERROR_SUCCESS != dwRes)
        {
            return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes);
        }
    }
    return E_FAIL;
}
 
 
//************************************************************************
//
// CLCDOutput::OnDraw
//
//************************************************************************
 
BOOL CLCDOutput::OnDraw(void)
{
    DWORD dwPriorityToUse = LGLCD_ASYNC_UPDATE(m_nPriority);
 
    if ( (NULL == m_pActivePage) ||
        (LGLCD_INVALID_DEVICE == m_hDevice) ||
        (LGLCD_PRIORITY_IDLE_NO_SHOW == dwPriorityToUse) )
    {
        // don't submit the bitmap
        return TRUE;
    }
 
    // Render the active screen
    m_pGfx->BeginDraw();
    m_pGfx->ClearScreen();
    m_pActivePage->OnDraw(*m_pGfx);
    m_pGfx->EndDraw(); 
 
    // Get the active bitmap
    lgLcdBitmap* pBitmap = m_pGfx->GetLCDScreen();
 
    // Only submit if the bitmap needs to be updated
    // (If the priority or bitmap have changed)
    DWORD res = ERROR_SUCCESS;
    if (DoesBitmapNeedUpdate(pBitmap))
    {
        res = lgLcdUpdateBitmap(m_hDevice, &pBitmap->bmp_mono.hdr, dwPriorityToUse);
        HandleErrorFromAPI(res);
    }
 
    return (LGLCD_INVALID_DEVICE != m_hDevice);
}
 
 
//************************************************************************
//
// CLCDOutput::OnUpdate
//
//************************************************************************
 
void CLCDOutput::OnUpdate(DWORD dwTimestamp)
{
    if (m_pActivePage)
    {
        m_pActivePage->OnUpdate(dwTimestamp);
    }
 
    // check for expiration
    if (m_pActivePage && m_pActivePage->HasExpired())
    {
        m_pActivePage = NULL;
        //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a 
        // program sets priority to LGLCD_PRIORITY_BACKGROUND, that 
        // priority sticks.
 
        OnPageExpired(m_pActivePage);
 
        // find the next active screen
        for (size_t i = 0; i < m_Objects.size(); i++)
        {
            CLCDPage *pPage = dynamic_cast<CLCDPage*>(m_Objects[i]);
            LCDUIASSERT(NULL != pPage);
 
            if (!pPage->HasExpired())
            {
                ShowPage(pPage);
                //m_nPriority = LGLCD_PRIORITY_FYI;  -> needs to go so that if a 
                // program sets priority to LGLCD_PRIORITY_BACKGROUND, that 
                // priority sticks.
                break;
            }
        }
 
        // if no screen found, empty the screen at idle priority
        if (NULL == m_pActivePage)
        {
            OnEnteringIdle();
            if (LGLCD_INVALID_DEVICE != m_hDevice)
            {
                m_pGfx->ClearScreen();
                lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr,
                    LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW));
            }
        }
    }
}
 
 
//************************************************************************
//
// CLCDOutput::GetSoftButtonState
//
//************************************************************************
 
DWORD CLCDOutput::GetSoftButtonState(void)
{
    return IsOpened() ? m_dwButtonState : 0;
}
 
 
//************************************************************************
//
// CLCDOutput::HandleErrorFromAPI
//
//************************************************************************
 
HRESULT CLCDOutput::HandleErrorFromAPI(DWORD dwRes)
{
    switch(dwRes)
    {
        // all is well
    case ERROR_SUCCESS:
    case RPC_S_PROTOCOL_ERROR:
        break;
        // we lost our device
    case ERROR_DEVICE_NOT_CONNECTED:
        LCDUITRACE(_T("lgLcdAPI returned with ERROR_DEVICE_NOT_CONNECTED, closing device\n"));
        Close();
        break;
    default:
        LCDUITRACE(_T("lgLcdAPI returned with other error (0x%08x) closing device\n"));
        Close();
        // something else happened, such as LCDMon that was terminated
        break;
    }
 
    if(ERROR_SUCCESS != dwRes)
    {
        return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes);
    }
 
    return S_OK;
}
 
 
//************************************************************************
//
// CLCDOutput::DoesBitmapNeedUpdate
//
//************************************************************************
 
BOOL CLCDOutput::DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap)
{
    UNREFERENCED_PARAMETER(pBitmap);
    // For now, always update
    return TRUE;
}
 
 
//************************************************************************
//
// CLCDOutput::OnPageExpired
//
//************************************************************************
 
void CLCDOutput::OnPageExpired(CLCDCollection* pScreen)
{
    UNREFERENCED_PARAMETER(pScreen);
}
 
 
//************************************************************************
//
// CLCDOutput::OnPageShown
//
//************************************************************************
 
void CLCDOutput::OnPageShown(CLCDCollection* pScreen)
{
    UNREFERENCED_PARAMETER(pScreen);
}
 
 
//************************************************************************
//
// CLCDOutput::OnEnteringIdle
//
//************************************************************************
 
void CLCDOutput::OnEnteringIdle(void)
{
}
 
 
//************************************************************************
//
// CLCDOutput::OnClosingDevice
//
//************************************************************************
 
void CLCDOutput::OnClosingDevice(int hDevice)
{
    UNREFERENCED_PARAMETER(hDevice);
}
 
 
//************************************************************************
//
// CLCDOutput::OnOpenedDevice
//
//************************************************************************
 
void CLCDOutput::OnOpenedDevice(int hDevice)
{
    UNREFERENCED_PARAMETER(hDevice);
}
 
 
//************************************************************************
//
// CLCDOutput::OnSoftButtonEvent
//
//************************************************************************
 
void CLCDOutput::OnSoftButtonEvent(DWORD dwButtonState)
{
    if (LGLCD_DEVICE_FAMILY_QVGA_BASIC == m_pGfx->GetFamily())
    {
        HandleButtonState(dwButtonState, LGLCDBUTTON_LEFT);
        HandleButtonState(dwButtonState, LGLCDBUTTON_RIGHT);
        HandleButtonState(dwButtonState, LGLCDBUTTON_OK);
        HandleButtonState(dwButtonState, LGLCDBUTTON_CANCEL);
        HandleButtonState(dwButtonState, LGLCDBUTTON_UP);
        HandleButtonState(dwButtonState, LGLCDBUTTON_DOWN);
        HandleButtonState(dwButtonState, LGLCDBUTTON_MENU);
    }
    else
    {
        HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON0);
        HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON1);
        HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON2);
        HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON3);
    }
 
    m_dwButtonState = dwButtonState;
}
 
 
//************************************************************************
//
// CLCDOutput::HandleButtonState
//
//************************************************************************
 
void CLCDOutput::HandleButtonState(DWORD dwButtonState, DWORD dwButton)
{
    if ( (m_dwButtonState & dwButton) && !(dwButtonState & dwButton) )
    {
        LCDUITRACE(_T("Button 0x%x released\n"), dwButton);
        OnLCDButtonUp(dwButton);
    }
    if ( !(m_dwButtonState & dwButton) && (dwButtonState & dwButton) )
    {
        LCDUITRACE(_T("Button 0x%x pressed\n"), dwButton);
        OnLCDButtonDown(dwButton);
    }
}
 
 
//************************************************************************
//
// CLCDOutput::OnLCDButtonDown
//
//************************************************************************
 
void CLCDOutput::OnLCDButtonDown(int nButton)
{
    if (m_pActivePage)
    {
        m_pActivePage->OnLCDButtonDown(nButton);
    }
}
 
 
//************************************************************************
//
// CLCDOutput::OnLCDButtonUp
//
//************************************************************************
 
void CLCDOutput::OnLCDButtonUp(int nButton)
{
    if (m_pActivePage)
    {
        m_pActivePage->OnLCDButtonUp(nButton);
    }
}
 
 
//************************************************************************
//
// CLCDOutput::GetDeviceId
//
//************************************************************************
 
int CLCDOutput::GetDeviceId(void)
{
    return m_hDevice;
}
 
 
//************************************************************************
//
// CLCDOutput::StopOpeningByDeviceType
//
//************************************************************************
 
void CLCDOutput::StopOpeningByDeviceType(void)
{
    m_OpenByTypeContext.deviceType = 0;
}
 
 
//************************************************************************
//
// CLCDOutput::HasBeenOpenedByDeviceType
//
//************************************************************************
 
BOOL CLCDOutput::HasBeenOpenedByDeviceType(void)
{
    return (0 != m_OpenByTypeContext.deviceType);
}
 
 
//** end of LCDOutput.cpp ************************************************

V522 There might be dereferencing of a potential null pointer 'pPage'.