[Libreoffice-commits] core.git: vcl/inc vcl/unx

Jan-Marek Glogowski glogow at fbihome.de
Thu Jul 13 13:08:31 UTC 2017


 vcl/inc/unx/gtk/gtkdata.hxx  |    4 -
 vcl/inc/unx/gtk/gtkinst.hxx  |    4 -
 vcl/unx/gtk/gtkdata.cxx      |  148 ++++++++++++++++++++++++++++++++++---------
 vcl/unx/gtk/gtkinst.cxx      |   25 ++++---
 vcl/unx/gtk3/gtk3gtkdata.cxx |  148 ++++++++++++++++++++++++++++++++++---------
 5 files changed, 259 insertions(+), 70 deletions(-)

New commits:
commit 9bc95521aaa35b533894b3934519acdbd7a47815
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Jul 13 14:57:21 2017 +0200

    Revert "GTK+ simplifiy system timer implementation"
    
    Current LO baseline doesn't have g_source_get_ready_time,
    so we keep the old stuff.
    
    This reverts commit 3e20ce802ee2ab49c4f2a98880f6e999657686bb.
    
    Change-Id: I32c39fa70c8d52cbb78620f528d60a986087dfd0

diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index 052fc071dcc0..2582314eb003 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -81,13 +81,15 @@ inline void widget_set_can_default(GtkWidget *widget, gboolean can_default)
 
 class GtkSalTimer : public SalTimer
 {
-    GSource *m_pTimeout;
+    struct SalGtkTimeoutSource *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
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
index ff8271b514a4..4c86a3d62867 100644
--- a/vcl/inc/unx/gtk/gtkinst.hxx
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
@@ -233,12 +233,12 @@ public:
             const cairo_font_options_t* GetLastSeenCairoFontOptions();
                                    void ResetLastSeenCairoFontOptions();
 
-    void                        RemoveTimer();
+    void                        RemoveTimer (SalTimer *pTimer);
 
     std::shared_ptr<vcl::unx::GtkPrintWrapper> const & getPrintWrapper() const;
 
 private:
-    GtkSalTimer*                m_pTimer;
+    std::vector<GtkSalTimer *>  m_aTimers;
 #if GTK_CHECK_VERSION(3,0,0)
     std::unordered_map< GdkAtom, css::uno::Reference<css::uno::XInterface> > m_aClipboards;
 #endif
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 )
diff --git a/vcl/unx/gtk3/gtk3gtkdata.cxx b/vcl/unx/gtk3/gtk3gtkdata.cxx
index 57cc1084460f..3e074489bfd5 100644
--- a/vcl/unx/gtk3/gtk3gtkdata.cxx
+++ b/vcl/unx/gtk3/gtk3gtkdata.cxx
@@ -614,71 +614,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;
     }
 }


More information about the Libreoffice-commits mailing list