blob: daae6eb1e387f88e0b07d1344b9c7de9816a48be [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sal/types.h>
#include <vcl/apptypes.hxx>
#include "svpinst.hxx"
#include "svpframe.hxx"
#include "svpdummies.hxx"
#include "svpvd.hxx"
#include "svpbmp.hxx"
#include <salframe.hxx>
#include <svdata.hxx>
#include <saldatabasic.hxx>
// plugin factory function
extern "C"
{
SAL_DLLPUBLIC_EXPORT SalInstance* create_SalInstance()
{
SvpSalInstance* pInstance = new SvpSalInstance();
SalData* pSalData = new SalData();
pSalData->m_pInstance = pInstance;
SetSalData( pSalData );
return pInstance;
}
}
bool SvpSalInstance::isFrameAlive( const SalFrame* pFrame ) const
{
for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
it != m_aFrames.end(); ++it )
{
if( *it == pFrame )
{
return true;
}
}
return false;
}
SvpSalInstance* SvpSalInstance::s_pDefaultInstance = NULL;
SvpSalInstance::SvpSalInstance()
{
m_aTimeout.tv_sec = 0;
m_aTimeout.tv_usec = 0;
m_nTimeoutMS = 0;
m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
if (pipe (m_pTimeoutFDS) != -1)
{
// initialize 'wakeup' pipe.
int flags;
// set close-on-exec descriptor flag.
if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
{
flags |= FD_CLOEXEC;
fcntl (m_pTimeoutFDS[0], F_SETFD, flags);
}
if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
{
flags |= FD_CLOEXEC;
fcntl (m_pTimeoutFDS[1], F_SETFD, flags);
}
// set non-blocking I/O flag.
if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1)
{
flags |= O_NONBLOCK;
fcntl (m_pTimeoutFDS[0], F_SETFL, flags);
}
if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1)
{
flags |= O_NONBLOCK;
fcntl (m_pTimeoutFDS[1], F_SETFL, flags);
}
}
m_aEventGuard = osl_createMutex();
if( s_pDefaultInstance == NULL )
s_pDefaultInstance = this;
}
SvpSalInstance::~SvpSalInstance()
{
if( s_pDefaultInstance == this )
s_pDefaultInstance = NULL;
// close 'wakeup' pipe.
close (m_pTimeoutFDS[0]);
close (m_pTimeoutFDS[1]);
osl_destroyMutex( m_aEventGuard );
}
void SvpSalInstance::PostEvent( const SalFrame* pFrame, void* pData, sal_uInt16 nEvent )
{
if( osl_acquireMutex( m_aEventGuard ) )
{
m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) );
osl_releaseMutex( m_aEventGuard );
}
Wakeup();
}
void SvpSalInstance::CancelEvent( const SalFrame* pFrame, void* pData, sal_uInt16 nEvent )
{
if( osl_acquireMutex( m_aEventGuard ) )
{
if( ! m_aUserEvents.empty() )
{
std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
do
{
if( it->m_pFrame == pFrame &&
it->m_pData == pData &&
it->m_nEvent == nEvent )
{
it = m_aUserEvents.erase( it );
}
else
++it;
} while( it != m_aUserEvents.end() );
}
osl_releaseMutex( m_aEventGuard );
}
}
void SvpSalInstance::deregisterFrame( SalFrame* pFrame )
{
m_aFrames.remove( pFrame );
if( osl_acquireMutex( m_aEventGuard ) )
{
// cancel outstanding events for this frame
if( ! m_aUserEvents.empty() )
{
std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
do
{
if( it->m_pFrame == pFrame )
{
it = m_aUserEvents.erase( it );
}
else
++it;
} while( it != m_aUserEvents.end() );
}
osl_releaseMutex( m_aEventGuard );
}
}
void SvpSalInstance::Wakeup()
{
write (m_pTimeoutFDS[1], "", 1);
}
// -=-= timeval =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
inline int operator >= ( const timeval &t1, const timeval &t2 )
{
if( t1.tv_sec == t2.tv_sec )
return t1.tv_usec >= t2.tv_usec;
return t1.tv_sec > t2.tv_sec;
}
inline timeval &operator += ( timeval &t1, sal_uLong t2 )
{
t1.tv_sec += t2 / 1000;
t1.tv_usec += t2 ? (t2 % 1000) * 1000 : 500;
if( t1.tv_usec > 1000000 )
{
t1.tv_sec++;
t1.tv_usec -= 1000000;
}
return t1;
}
inline int operator > ( const timeval &t1, const timeval &t2 )
{
if( t1.tv_sec == t2.tv_sec )
return t1.tv_usec > t2.tv_usec;
return t1.tv_sec > t2.tv_sec;
}
bool SvpSalInstance::CheckTimeout( bool bExecuteTimers )
{
bool bRet = false;
if( m_aTimeout.tv_sec ) // timer is started
{
timeval aTimeOfDay;
gettimeofday( &aTimeOfDay, 0 );
if( aTimeOfDay >= m_aTimeout )
{
bRet = true;
if( bExecuteTimers )
{
// timed out, update timeout
m_aTimeout = aTimeOfDay;
m_aTimeout += m_nTimeoutMS;
// notify
ImplSVData* pSVData = ImplGetSVData();
if( pSVData->mpSalTimer )
pSVData->mpSalTimer->CallCallback();
}
}
}
return bRet;
}
SalFrame* SvpSalInstance::CreateChildFrame( SystemParentData* pParent, sal_uLong nStyle )
{
return new SvpSalFrame( this, NULL, nStyle, pParent );
}
SalFrame* SvpSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nStyle )
{
return new SvpSalFrame( this, pParent, nStyle );
}
void SvpSalInstance::DestroyFrame( SalFrame* pFrame )
{
delete pFrame;
}
SalObject* SvpSalInstance::CreateObject( SalFrame*, SystemWindowData*, sal_Bool )
{
return new SvpSalObject();
}
void SvpSalInstance::DestroyObject( SalObject* pObject )
{
delete pObject;
}
SalVirtualDevice* SvpSalInstance::CreateVirtualDevice( SalGraphics*,
long nDX, long nDY,
sal_uInt16 nBitCount, const SystemGraphicsData* )
{
SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice( nBitCount );
pNew->SetSize( nDX, nDY );
return pNew;
}
void SvpSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
{
delete pDevice;
}
SalTimer* SvpSalInstance::CreateSalTimer()
{
return new SvpSalTimer( this );
}
SalI18NImeStatus* SvpSalInstance::CreateI18NImeStatus()
{
return new SvpImeStatus();
}
SalSystem* SvpSalInstance::CreateSalSystem()
{
return new SvpSalSystem();
}
SalBitmap* SvpSalInstance::CreateSalBitmap()
{
return new SvpSalBitmap();
}
vos::IMutex* SvpSalInstance::GetYieldMutex()
{
return &m_aYieldMutex;
}
sal_uLong SvpSalInstance::ReleaseYieldMutex()
{
if ( m_aYieldMutex.GetThreadId() ==
vos::OThread::getCurrentIdentifier() )
{
sal_uLong nCount = m_aYieldMutex.GetAcquireCount();
sal_uLong n = nCount;
while ( n )
{
m_aYieldMutex.release();
n--;
}
return nCount;
}
else
return 0;
}
void SvpSalInstance::AcquireYieldMutex( sal_uLong nCount )
{
while ( nCount )
{
m_aYieldMutex.acquire();
nCount--;
}
}
bool SvpSalInstance::CheckYieldMutex()
{
bool bRet = true;
if ( m_aYieldMutex.GetThreadId() !=
vos::OThread::getCurrentIdentifier() )
{
bRet = false;
}
return bRet;
}
void SvpSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
{
// first, check for already queued events.
// release yield mutex
std::list< SalUserEvent > aEvents;
sal_uLong nAcquireCount = ReleaseYieldMutex();
if( osl_acquireMutex( m_aEventGuard ) )
{
if( ! m_aUserEvents.empty() )
{
if( bHandleAllCurrentEvents )
{
aEvents = m_aUserEvents;
m_aUserEvents.clear();
}
else
{
aEvents.push_back( m_aUserEvents.front() );
m_aUserEvents.pop_front();
}
}
osl_releaseMutex( m_aEventGuard );
}
// acquire yield mutex again
AcquireYieldMutex( nAcquireCount );
bool bEvent = !aEvents.empty();
if( bEvent )
{
for( std::list<SalUserEvent>::const_iterator it = aEvents.begin(); it != aEvents.end(); ++it )
{
if ( isFrameAlive( it->m_pFrame ) )
{
it->m_pFrame->CallCallback( it->m_nEvent, it->m_pData );
if( it->m_nEvent == SALEVENT_RESIZE )
{
// this would be a good time to post a paint
const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>(it->m_pFrame);
pSvpFrame->PostPaint();
}
}
}
}
bEvent = CheckTimeout() || bEvent;
if (bWait && ! bEvent )
{
int nTimeoutMS = 0;
if (m_aTimeout.tv_sec) // Timer is started.
{
timeval Timeout;
// determine remaining timeout.
gettimeofday (&Timeout, 0);
nTimeoutMS = m_aTimeout.tv_sec*1000 + m_aTimeout.tv_usec/1000
- Timeout.tv_sec*1000 - Timeout.tv_usec/1000;
if( nTimeoutMS < 0 )
nTimeoutMS = 0;
}
else
nTimeoutMS = -1; // wait until something happens
// release yield mutex
nAcquireCount = ReleaseYieldMutex();
// poll
struct pollfd aPoll;
aPoll.fd = m_pTimeoutFDS[0];
aPoll.events = POLLIN;
aPoll.revents = 0;
poll( &aPoll, 1, nTimeoutMS );
// acquire yield mutex again
AcquireYieldMutex( nAcquireCount );
// clean up pipe
if( (aPoll.revents & POLLIN) != 0 )
{
int buffer;
while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
continue;
}
}
}
bool SvpSalInstance::AnyInput( sal_uInt16 nType )
{
if( (nType & INPUT_TIMER) != 0 )
return CheckTimeout( false );
return false;
}
SalSession* SvpSalInstance::CreateSalSession()
{
return NULL;
}
void* SvpSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
{
rReturnedBytes = 1;
rReturnedType = AsciiCString;
return const_cast<char*>("");
}
// -------------------------------------------------------------------------
//
// SalYieldMutex
//
// -------------------------------------------------------------------------
SvpSalYieldMutex::SvpSalYieldMutex()
{
mnCount = 0;
mnThreadId = 0;
}
void SvpSalYieldMutex::acquire()
{
OMutex::acquire();
mnThreadId = vos::OThread::getCurrentIdentifier();
mnCount++;
}
void SvpSalYieldMutex::release()
{
if ( mnThreadId == vos::OThread::getCurrentIdentifier() )
{
if ( mnCount == 1 )
mnThreadId = 0;
mnCount--;
}
OMutex::release();
}
sal_Bool SvpSalYieldMutex::tryToAcquire()
{
if ( OMutex::tryToAcquire() )
{
mnThreadId = vos::OThread::getCurrentIdentifier();
mnCount++;
return sal_True;
}
else
return sal_False;
}
// ---------------
// - SalTimer -
// ---------------
void SvpSalInstance::StopTimer()
{
m_aTimeout.tv_sec = 0;
m_aTimeout.tv_usec = 0;
m_nTimeoutMS = 0;
}
void SvpSalInstance::StartTimer( sal_uLong nMS )
{
timeval Timeout (m_aTimeout); // previous timeout.
gettimeofday (&m_aTimeout, 0);
m_nTimeoutMS = nMS;
m_aTimeout += m_nTimeoutMS;
if ((Timeout > m_aTimeout) || (Timeout.tv_sec == 0))
{
// Wakeup from previous timeout (or stopped timer).
Wakeup();
}
}
void SvpSalInstance::AddToRecentDocumentList(const rtl::OUString&, const rtl::OUString&)
{
}
SvpSalTimer::~SvpSalTimer()
{
}
void SvpSalTimer::Stop()
{
m_pInstance->StopTimer();
}
void SvpSalTimer::Start( sal_uLong nMS )
{
m_pInstance->StartTimer( nMS );
}