Kaydet (Commit) 3e20ce80 authored tarafından Jan-Marek Glogowski's avatar Jan-Marek Glogowski

GTK+ simplifiy system timer implementation

Instead of implementing an own GSource, this implements the glib
based system timer using the g_timeout_source_new() function.

It removes the vector of GtkSalTimer and changes the remaining
timer to be single-shot, just like the Windows and KDE platforms.

The ownership handling is a little bit strange and should generally
be changed to use std::shared_ptr as the result of CreateSalTimer
for all backends.

Change-Id: Iea40a6284bdc5c121235af5a6079a92a679391ca
üst 1fedc1c3
......@@ -81,15 +81,13 @@ inline void widget_set_can_default(GtkWidget *widget, gboolean can_default)
class GtkSalTimer : public SalTimer
{
struct SalGtkTimeoutSource *m_pTimeout;
GSource *m_pTimeout;
public:
GtkSalTimer();
virtual ~GtkSalTimer() override;
virtual void Start( sal_uLong nMS ) override;
virtual void Stop() override;
bool Expired();
sal_uLong m_nTimeoutMS;
};
class GtkData : public SalGenericData
......
......@@ -233,12 +233,12 @@ public:
const cairo_font_options_t* GetLastSeenCairoFontOptions();
void ResetLastSeenCairoFontOptions();
void RemoveTimer (SalTimer *pTimer);
void RemoveTimer();
std::shared_ptr<vcl::unx::GtkPrintWrapper> const & getPrintWrapper() const;
private:
std::vector<GtkSalTimer *> m_aTimers;
GtkSalTimer* m_pTimer;
#if GTK_CHECK_VERSION(3,0,0)
std::unordered_map< GdkAtom, css::uno::Reference<css::uno::XInterface> > m_aClipboards;
#endif
......
......@@ -652,161 +652,71 @@ bool GtkData::ErrorTrapPop( bool bIgnoreError )
return gdk_error_trap_pop () != 0;
}
extern "C" {
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 ) );
}
#if !GLIB_CHECK_VERSION(2,32,0)
#define G_SOURCE_REMOVE FALSE
#endif
static gboolean sal_gtk_timeout_dispatch( GSource *pSource, GSourceFunc, gpointer )
extern "C" {
static gboolean sal_gtk_timeout_function( 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 TRUE;
return G_SOURCE_REMOVE;
}
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( this );
pInstance->RemoveTimer();
Stop();
}
bool GtkSalTimer::Expired()
{
if( !m_pTimeout )
if( !m_pTimeout || g_source_is_destroyed( m_pTimeout ) )
return false;
gint nDummy = 0;
GTimeVal aTimeNow;
g_get_current_time( &aTimeNow );
return !!sal_gtk_timeout_expired( m_pTimeout, &nDummy, &aTimeNow);
return (g_get_monotonic_time() > g_source_get_ready_time( m_pTimeout ));
}
void GtkSalTimer::Start( sal_uLong nMS )
{
// glib is not 64bit safe in this regard.
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 );
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
}
void GtkSalTimer::Stop()
{
if( m_pTimeout )
{
g_source_destroy( &m_pTimeout->aParent );
g_source_unref( &m_pTimeout->aParent );
g_source_destroy( m_pTimeout );
g_source_unref( m_pTimeout );
m_pTimeout = nullptr;
}
}
......
......@@ -156,6 +156,7 @@ GtkInstance::GtkInstance( SalYieldMutex* pMutex )
#else
: X11SalInstance( pMutex )
#endif
, m_pTimer(nullptr)
, bNeedsInit(true)
, m_pLastCairoFontOptions(nullptr)
{
......@@ -194,8 +195,7 @@ void GtkInstance::EnsureInit()
GtkInstance::~GtkInstance()
{
while( !m_aTimers.empty() )
delete *m_aTimers.begin();
assert( nullptr == m_pTimer );
DeInitAtkBridge();
ResetLastSeenCairoFontOptions();
}
......@@ -397,18 +397,16 @@ void GtkInstance::DestroyMenuItem( SalMenuItem* ) {}
SalTimer* GtkInstance::CreateSalTimer()
{
EnsureInit();
GtkSalTimer *pTimer = new GtkSalTimer();
m_aTimers.push_back( pTimer );
return pTimer;
assert( nullptr == m_pTimer );
if ( nullptr == m_pTimer )
m_pTimer = new GtkSalTimer();
return m_pTimer;
}
void GtkInstance::RemoveTimer (SalTimer *pTimer)
void GtkInstance::RemoveTimer()
{
EnsureInit();
std::vector<GtkSalTimer *>::iterator it;
it = std::find( m_aTimers.begin(), m_aTimers.end(), pTimer );
if( it != m_aTimers.end() )
m_aTimers.erase( it );
m_pTimer = nullptr;
}
bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
......@@ -422,12 +420,7 @@ bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong co
bool GtkInstance::IsTimerExpired()
{
EnsureInit();
for( std::vector<GtkSalTimer *>::iterator it = m_aTimers.begin();
it != m_aTimers.end(); ++it )
if( (*it)->Expired() )
return true;
return false;
return (m_pTimer && m_pTimer->Expired());
}
bool GtkInstance::AnyInput( VclInputFlags nType )
......
......@@ -614,161 +614,71 @@ bool GtkData::ErrorTrapPop( bool bIgnoreError )
return gdk_error_trap_pop () != 0;
}
extern "C" {
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 ) );
}
#if !GLIB_CHECK_VERSION(2,32,0)
#define G_SOURCE_REMOVE FALSE
#endif
static gboolean sal_gtk_timeout_dispatch( GSource *pSource, GSourceFunc, gpointer )
extern "C" {
static gboolean sal_gtk_timeout_function( 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 TRUE;
return G_SOURCE_REMOVE;
}
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( this );
pInstance->RemoveTimer();
Stop();
}
bool GtkSalTimer::Expired()
{
if( !m_pTimeout )
if( !m_pTimeout || g_source_is_destroyed( m_pTimeout ) )
return false;
gint nDummy = 0;
GTimeVal aTimeNow;
g_get_current_time( &aTimeNow );
return !!sal_gtk_timeout_expired( m_pTimeout, &nDummy, &aTimeNow);
return (g_get_monotonic_time() > g_source_get_ready_time( m_pTimeout ));
}
void GtkSalTimer::Start( sal_uLong nMS )
{
// glib is not 64bit safe in this regard.
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 );
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
}
void GtkSalTimer::Stop()
{
if( m_pTimeout )
{
g_source_destroy( &m_pTimeout->aParent );
g_source_unref( &m_pTimeout->aParent );
g_source_destroy( m_pTimeout );
g_source_unref( m_pTimeout );
m_pTimeout = nullptr;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment