/************************************************************** * * 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 #include #include #include #include #include #include "svpinst.hxx" #include "svpframe.hxx" #include "svpdummies.hxx" #include "svpvd.hxx" #include "svpbmp.hxx" #include #include #include // 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::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(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(""); } // ------------------------------------------------------------------------- // // 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 ); }