summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk')
-rw-r--r--vcl/unx/gtk/gtkdata.cxx148
-rw-r--r--vcl/unx/gtk/gtkinst.cxx25
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 )