diff options
Diffstat (limited to 'vcl/unx/gtk')
-rw-r--r-- | vcl/unx/gtk/gtkdata.cxx | 148 | ||||
-rw-r--r-- | vcl/unx/gtk/gtkinst.cxx | 25 |
2 files changed, 135 insertions, 38 deletions
diff --git a/vcl/unx/gtk/gtkdata.cxx b/vcl/unx/gtk/gtkdata.cxx index 76c9fed0e733..e5278f157698 100644 --- a/vcl/unx/gtk/gtkdata.cxx +++ b/vcl/unx/gtk/gtkdata.cxx @@ -652,71 +652,161 @@ bool GtkData::ErrorTrapPop( bool bIgnoreError ) return gdk_error_trap_pop () != 0; } -#if !GLIB_CHECK_VERSION(2,32,0) -#define G_SOURCE_REMOVE FALSE -#endif - extern "C" { - static gboolean sal_gtk_timeout_function( gpointer ) + + struct SalGtkTimeoutSource { + GSource aParent; + GTimeVal aFireTime; + GtkSalTimer *pInstance; + }; + + static void sal_gtk_timeout_defer( SalGtkTimeoutSource *pTSource ) + { + g_get_current_time( &pTSource->aFireTime ); + g_time_val_add( &pTSource->aFireTime, pTSource->pInstance->m_nTimeoutMS * 1000 ); + } + + static gboolean sal_gtk_timeout_expired( SalGtkTimeoutSource *pTSource, + gint *nTimeoutMS, GTimeVal *pTimeNow ) + { + glong nDeltaSec = pTSource->aFireTime.tv_sec - pTimeNow->tv_sec; + glong nDeltaUSec = pTSource->aFireTime.tv_usec - pTimeNow->tv_usec; + if( nDeltaSec < 0 || ( nDeltaSec == 0 && nDeltaUSec < 0) ) + { + *nTimeoutMS = 0; + return TRUE; + } + if( nDeltaUSec < 0 ) + { + nDeltaUSec += 1000000; + nDeltaSec -= 1; + } + // if the clock changes backwards we need to cope ... + if( (unsigned long) nDeltaSec > 1 + ( pTSource->pInstance->m_nTimeoutMS / 1000 ) ) + { + sal_gtk_timeout_defer( pTSource ); + return TRUE; + } + + *nTimeoutMS = MIN( G_MAXINT, ( nDeltaSec * 1000 + (nDeltaUSec + 999) / 1000 ) ); + + return *nTimeoutMS == 0; + } + + static gboolean sal_gtk_timeout_prepare( GSource *pSource, gint *nTimeoutMS ) { + SalGtkTimeoutSource *pTSource = reinterpret_cast<SalGtkTimeoutSource *>(pSource); + + GTimeVal aTimeNow; + g_get_current_time( &aTimeNow ); + + return sal_gtk_timeout_expired( pTSource, nTimeoutMS, &aTimeNow ); + } + + static gboolean sal_gtk_timeout_check( GSource *pSource ) + { + SalGtkTimeoutSource *pTSource = reinterpret_cast<SalGtkTimeoutSource *>(pSource); + + GTimeVal aTimeNow; + g_get_current_time( &aTimeNow ); + + return ( pTSource->aFireTime.tv_sec < aTimeNow.tv_sec || + ( pTSource->aFireTime.tv_sec == aTimeNow.tv_sec && + pTSource->aFireTime.tv_usec < aTimeNow.tv_usec ) ); + } + + static gboolean sal_gtk_timeout_dispatch( GSource *pSource, GSourceFunc, gpointer ) + { + SalGtkTimeoutSource *pTSource = reinterpret_cast<SalGtkTimeoutSource *>(pSource); + + if( !pTSource->pInstance ) + return FALSE; + GtkData *pSalData = static_cast< GtkData* >( GetSalData()); + osl::Guard< comphelper::SolarMutex > aGuard( pSalData->m_pInstance->GetYieldMutex() ); + sal_gtk_timeout_defer( pTSource ); + ImplSVData* pSVData = ImplGetSVData(); if( pSVData->maSchedCtx.mpSalTimer ) pSVData->maSchedCtx.mpSalTimer->CallCallback(); - return G_SOURCE_REMOVE; + + return TRUE; } + + static GSourceFuncs sal_gtk_timeout_funcs = + { + sal_gtk_timeout_prepare, + sal_gtk_timeout_check, + sal_gtk_timeout_dispatch, + nullptr, nullptr, nullptr + }; +} + +static SalGtkTimeoutSource * +create_sal_gtk_timeout( GtkSalTimer *pTimer ) +{ + GSource *pSource = g_source_new( &sal_gtk_timeout_funcs, sizeof( SalGtkTimeoutSource ) ); + SalGtkTimeoutSource *pTSource = reinterpret_cast<SalGtkTimeoutSource *>(pSource); + pTSource->pInstance = pTimer; + + // #i36226# timers should be executed with lower priority + // than XEvents like in generic plugin + g_source_set_priority( pSource, G_PRIORITY_LOW ); + g_source_set_can_recurse( pSource, TRUE ); + g_source_set_callback( pSource, + /* unused dummy */ g_idle_remove_by_data, + nullptr, nullptr ); + g_source_attach( pSource, g_main_context_default() ); +#ifdef DBG_UTIL + g_source_set_name( pSource, "VCL timeout source" ); +#endif + + sal_gtk_timeout_defer( pTSource ); + + return pTSource; } GtkSalTimer::GtkSalTimer() : m_pTimeout(nullptr) + , m_nTimeoutMS(0) { } GtkSalTimer::~GtkSalTimer() { GtkInstance *pInstance = static_cast<GtkInstance *>(GetSalData()->m_pInstance); - pInstance->RemoveTimer(); + pInstance->RemoveTimer( this ); Stop(); } bool GtkSalTimer::Expired() { - if( !m_pTimeout || g_source_is_destroyed( m_pTimeout ) ) + if( !m_pTimeout ) return false; - return (g_get_monotonic_time() > g_source_get_ready_time( m_pTimeout )); + + gint nDummy = 0; + GTimeVal aTimeNow; + g_get_current_time( &aTimeNow ); + return !!sal_gtk_timeout_expired( m_pTimeout, &nDummy, &aTimeNow); } void GtkSalTimer::Start( sal_uLong nMS ) { // glib is not 64bit safe in this regard. - if ( nMS > G_MAXINT ) - nMS = G_MAXINT; - - Stop(); - assert( nullptr == m_pTimeout ); - - m_pTimeout = g_timeout_source_new ( nMS ); - // #i36226# timers should be executed with lower priority - // than XEvents like in generic plugin - g_source_set_priority( m_pTimeout, G_PRIORITY_LOW ); - g_source_set_can_recurse( m_pTimeout, TRUE ); - g_source_set_callback( m_pTimeout, - sal_gtk_timeout_function, - this, nullptr ); - g_source_attach( m_pTimeout, g_main_context_default() ); -#ifdef DBG_UTIL - g_source_set_name( m_pTimeout, "VCL timeout source" ); -#endif + assert( nMS <= G_MAXINT ); + m_nTimeoutMS = nMS; // for restarting + Stop(); // FIXME: ideally re-use an existing m_pTimeout + m_pTimeout = create_sal_gtk_timeout( this ); } void GtkSalTimer::Stop() { if( m_pTimeout ) { - g_source_destroy( m_pTimeout ); - g_source_unref( m_pTimeout ); + g_source_destroy( &m_pTimeout->aParent ); + g_source_unref( &m_pTimeout->aParent ); m_pTimeout = nullptr; } } diff --git a/vcl/unx/gtk/gtkinst.cxx b/vcl/unx/gtk/gtkinst.cxx index caaa2af2499f..034b634a0f79 100644 --- a/vcl/unx/gtk/gtkinst.cxx +++ b/vcl/unx/gtk/gtkinst.cxx @@ -156,7 +156,6 @@ GtkInstance::GtkInstance( SalYieldMutex* pMutex ) #else : X11SalInstance( pMutex ) #endif - , m_pTimer(nullptr) , bNeedsInit(true) , m_pLastCairoFontOptions(nullptr) { @@ -195,7 +194,8 @@ void GtkInstance::EnsureInit() GtkInstance::~GtkInstance() { - assert( nullptr == m_pTimer ); + while( !m_aTimers.empty() ) + delete *m_aTimers.begin(); DeInitAtkBridge(); ResetLastSeenCairoFontOptions(); } @@ -397,16 +397,18 @@ void GtkInstance::DestroyMenuItem( SalMenuItem* ) {} SalTimer* GtkInstance::CreateSalTimer() { EnsureInit(); - assert( nullptr == m_pTimer ); - if ( nullptr == m_pTimer ) - m_pTimer = new GtkSalTimer(); - return m_pTimer; + GtkSalTimer *pTimer = new GtkSalTimer(); + m_aTimers.push_back( pTimer ); + return pTimer; } -void GtkInstance::RemoveTimer() +void GtkInstance::RemoveTimer (SalTimer *pTimer) { EnsureInit(); - m_pTimer = nullptr; + std::vector<GtkSalTimer *>::iterator it; + it = std::find( m_aTimers.begin(), m_aTimers.end(), pTimer ); + if( it != m_aTimers.end() ) + m_aTimers.erase( it ); } bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased) @@ -420,7 +422,12 @@ bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong co bool GtkInstance::IsTimerExpired() { EnsureInit(); - return (m_pTimer && m_pTimer->Expired()); + for( std::vector<GtkSalTimer *>::iterator it = m_aTimers.begin(); + it != m_aTimers.end(); ++it ) + if( (*it)->Expired() ) + return true; + + return false; } bool GtkInstance::AnyInput( VclInputFlags nType ) |