a9add1
From de66d2e73cf44d2691d7e2e4ca8df98b46b26c10 Mon Sep 17 00:00:00 2001
a9add1
From: Michael Meeks <michael.meeks@collabora.com>
a9add1
Date: Fri, 13 Nov 2015 09:56:53 +0000
a9add1
Subject: [PATCH] backport 5-1 idle/timers loop to 5-0
a9add1
a9add1
slideshow: cleanup main-loop usage, post-yield listeners, etc.
a9add1
a9add1
    This removes several attempts at reducing jitter in slideshow
a9add1
animations. Now we have high-resolution (ie. not clamped to 10ms)
a9add1
timers on Windows and a cleaner and simpler main-loop, we should
a9add1
be able to use generic timer code-paths for all of this.
a9add1
a9add1
    This also allows us to further cleanup and simplify the main-loop
a9add1
removing the now redundent post-yield handler concept. If there is a
a9add1
short enough timeout, we will take just 1ms of delay before executing
a9add1
a short timer anyway.
a9add1
a9add1
    Also removed some lingering comments from an old attempt to boost
a9add1
priorities which broken audio playback.
a9add1
a9add1
    Tested: tdf#32861 - still works, audio still plays, no new jitter
a9add1
            in animations that I tested.
a9add1
a9add1
Reviewed-on: https://gerrit.libreoffice.org/19947
a9add1
Tested-by: Jenkins <ci@libreoffice.org>
a9add1
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
a9add1
(cherry picked from commit 12dcf5e6e770b1933252a1f919663ba45ded4cdf)
a9add1
a9add1
Change-Id: Iadc5e2a48828a18a599a86a8df14cb2b75dd425e
a9add1
---
a9add1
 .../source/primitive2d/textlayoutdevice.cxx        |   5 +-
a9add1
 framework/source/services/autorecovery.cxx         |   1 +
a9add1
 include/sal/log-areas.dox                          |   1 +
a9add1
 include/vcl/idle.hxx                               |   5 +-
a9add1
 include/vcl/scheduler.hxx                          |  48 +++---
a9add1
 include/vcl/svapp.hxx                              |  74 +---------
a9add1
 include/vcl/timer.hxx                              |   9 +-
a9add1
 sd/source/ui/slideshow/slideshowimpl.cxx           |  47 +-----
a9add1
 sd/source/ui/slideshow/slideshowimpl.hxx           |   3 +-
a9add1
 toolkit/source/awt/vclxtoolkit.cxx                 |   2 +-
a9add1
 vcl/headless/svpinst.cxx                           |   7 +-
a9add1
 vcl/inc/headless/svpinst.hxx                       |   2 +-
a9add1
 vcl/inc/osx/salinst.h                              |   2 +-
a9add1
 vcl/inc/salinst.hxx                                |  13 +-
a9add1
 vcl/inc/saltimer.hxx                               |  17 +++
a9add1
 vcl/inc/svdata.hxx                                 |   4 -
a9add1
 vcl/inc/unx/gtk/gtkdata.hxx                        |   2 +-
a9add1
 vcl/inc/unx/gtk/gtkinst.hxx                        |   2 +-
a9add1
 vcl/inc/unx/saldisp.hxx                            |   4 +-
a9add1
 vcl/inc/unx/salinst.h                              |   2 +-
a9add1
 vcl/inc/win/salinst.h                              |   2 +-
a9add1
 vcl/osx/salinst.cxx                                |  13 +-
a9add1
 vcl/qa/cppunit/timer.cxx                           |   2 +-
a9add1
 vcl/source/app/idle.cxx                            |  26 ++--
a9add1
 vcl/source/app/scheduler.cxx                       | 164 +++++++++++++++------
a9add1
 vcl/source/app/svapp.cxx                           |  99 +++++++------
a9add1
 vcl/source/app/svmain.cxx                          |   5 -
a9add1
 vcl/source/app/timer.cxx                           |  84 ++++-------
a9add1
 vcl/unx/generic/app/saldata.cxx                    |  13 +-
a9add1
 vcl/unx/generic/app/saldisp.cxx                    |   9 +-
a9add1
 vcl/unx/generic/app/salinst.cxx                    |   6 +-
a9add1
 vcl/unx/gtk/a11y/atkwrapper.cxx                    |   2 +-
a9add1
 vcl/unx/gtk/app/gtkdata.cxx                        |  14 +-
a9add1
 vcl/unx/gtk/app/gtkinst.cxx                        |   6 +-
a9add1
 vcl/unx/kde4/KDESalDisplay.cxx                     |   9 +-
a9add1
 vcl/unx/kde4/KDESalDisplay.hxx                     |   2 +-
a9add1
 vcl/unx/kde4/KDEXLib.cxx                           |  16 +-
a9add1
 vcl/unx/kde4/KDEXLib.hxx                           |   4 +-
a9add1
 vcl/win/source/app/salinst.cxx                     |  19 ++-
a9add1
 39 files changed, 390 insertions(+), 355 deletions(-)
a9add1
a9add1
diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
a9add1
index 2eefc3f..99dad74 100644
a9add1
--- a/drawinglayer/source/primitive2d/textlayoutdevice.cxx
a9add1
+++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
a9add1
@@ -72,8 +72,9 @@ namespace
a9add1
     };
a9add1
 
a9add1
     ImpTimedRefDev::ImpTimedRefDev(scoped_timed_RefDev& rOwnerOfMe)
a9add1
-    :   mrOwnerOfMe(rOwnerOfMe),
a9add1
-        mpVirDev(0L),
a9add1
+    :   Timer( "Timer to destroy drawinglayer reference device" ),
a9add1
+        mrOwnerOfMe(rOwnerOfMe),
a9add1
+        mpVirDev(nullptr),
a9add1
         mnUseCount(0L)
a9add1
     {
a9add1
         SetTimeout(3L * 60L * 1000L); // three minutes
a9add1
diff --git a/framework/source/services/autorecovery.cxx b/framework/source/services/autorecovery.cxx
a9add1
index 8b75271..36adb9b 100644
a9add1
--- a/framework/source/services/autorecovery.cxx
a9add1
+++ b/framework/source/services/autorecovery.cxx
a9add1
@@ -1261,6 +1261,7 @@ AutoRecovery::AutoRecovery(const css::uno::Reference< css::uno::XComponentContex
a9add1
     , m_bListenForConfigChanges (false                                          )
a9add1
     , m_nAutoSaveTimeIntervall  (0                                                  )
a9add1
     , m_eJob                    (AutoRecovery::E_NO_JOB                             )
a9add1
+    , m_aTimer                  ( "Auto save timer" )
a9add1
     , m_aAsyncDispatcher        ( LINK( this, AutoRecovery, implts_asyncDispatch )  )
a9add1
     , m_eTimerType              (E_DONT_START_TIMER                                 )
a9add1
     , m_nIdPool                 (0                                                  )
a9add1
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
a9add1
index d734876..6cb1348 100644
a9add1
--- a/include/sal/log-areas.dox
a9add1
+++ b/include/sal/log-areas.dox
a9add1
@@ -403,6 +403,7 @@ certain functionality.
a9add1
 @li @c vcl.osx
a9add1
 @li @c vcl.osx.print
a9add1
 @li @c vcl.quartz
a9add1
+@li @c vcl.schedule - scheduler / main-loop information
a9add1
 @li @c vcl.scrollbar - Scroll Bars
a9add1
 @li @c vcl.sm - Session Manager
a9add1
 @li @c vcl.unity
a9add1
diff --git a/include/vcl/idle.hxx b/include/vcl/idle.hxx
a9add1
index 2e853b7..ba892a9 100644
a9add1
--- a/include/vcl/idle.hxx
a9add1
+++ b/include/vcl/idle.hxx
a9add1
@@ -39,8 +39,9 @@ public:
a9add1
     void            SetIdleHdl( const Link<Idle *, void>& rLink ) { maIdleHdl = rLink; }
a9add1
     const Link<Idle *, void>& GetIdleHdl() const { return maIdleHdl; }
a9add1
     virtual void Invoke() SAL_OVERRIDE;
a9add1
-    virtual bool ReadyForSchedule( bool bTimer ) SAL_OVERRIDE;
a9add1
-    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) SAL_OVERRIDE;
a9add1
+    virtual bool ReadyForSchedule( bool bTimerOnly, sal_uInt64 nTimeNow ) const SAL_OVERRIDE;
a9add1
+    virtual bool IsIdle() const SAL_OVERRIDE;
a9add1
+    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) const SAL_OVERRIDE;
a9add1
     Idle&           operator=( const Idle& rIdle );
a9add1
 };
a9add1
 
a9add1
diff --git a/include/vcl/scheduler.hxx b/include/vcl/scheduler.hxx
a9add1
index 973565b..d9a8678 100644
a9add1
--- a/include/vcl/scheduler.hxx
a9add1
+++ b/include/vcl/scheduler.hxx
a9add1
@@ -22,21 +22,9 @@
a9add1
 
a9add1
 #include <vcl/dllapi.h>
a9add1
 
a9add1
-struct ImplSVData;
a9add1
 class Scheduler;
a9add1
-struct ImplSchedulerData
a9add1
-{
a9add1
-    ImplSchedulerData*  mpNext;      // Pointer to the next element in list
a9add1
-    Scheduler*          mpScheduler;      // Pointer to VCL Scheduler instance
a9add1
-    bool                mbDelete;    // Destroy this scheduler?
a9add1
-    bool                mbInScheduler;    // Scheduler currently processed?
a9add1
-    sal_uInt64          mnUpdateTime;   // Last Update Time
a9add1
-    sal_uInt32          mnUpdateStack;  // Update Stack
a9add1
-
a9add1
-    void Invoke();
a9add1
-
a9add1
-    static ImplSchedulerData *GetMostImportantTask( bool bTimer );
a9add1
-};
a9add1
+struct ImplSVData;
a9add1
+struct ImplSchedulerData;
a9add1
 
a9add1
 enum class SchedulerPriority {
a9add1
     HIGHEST   = 0,
a9add1
@@ -51,23 +39,39 @@ enum class SchedulerPriority {
a9add1
 
a9add1
 class VCL_DLLPUBLIC Scheduler
a9add1
 {
a9add1
+private:
a9add1
+    static void InitSystemTimer(ImplSVData* pSVData);
a9add1
+
a9add1
 protected:
a9add1
     ImplSchedulerData*  mpSchedulerData;    /// Pointer to element in scheduler list
a9add1
     const sal_Char     *mpDebugName;        /// Useful for debugging
a9add1
     SchedulerPriority   mePriority;         /// Scheduler priority
a9add1
     bool                mbActive;           /// Currently in the scheduler
a9add1
 
a9add1
+    // These should be constexpr static, when supported.
a9add1
+    static const sal_uInt64 ImmediateTimeoutMs = 1;
a9add1
+    static const sal_uInt64 MaximumTimeoutMs = 1000 * 60; // 1 minute
a9add1
+
a9add1
+    static void ImplStartTimer(sal_uInt64 nMS, bool bForce = false);
a9add1
+
a9add1
     friend struct ImplSchedulerData;
a9add1
     virtual void SetDeletionFlags();
a9add1
-    virtual bool ReadyForSchedule( bool bTimer ) = 0;
a9add1
-    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) = 0;
a9add1
+    /// Is this item ready to be dispatched at @nTimeNow
a9add1
+    virtual bool ReadyForSchedule( bool bTimerOnly, sal_uInt64 nTimeNow ) const = 0;
a9add1
+    /// Schedule only when other timers and events are processed
a9add1
+    virtual bool IsIdle() const = 0;
a9add1
+    /**
a9add1
+     * Adjust @nMinPeriod downwards if we want to be notified before
a9add1
+     * then, @nTimeNow is the current time.
a9add1
+     */
a9add1
+    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTimeNow ) const = 0;
a9add1
 
a9add1
 public:
a9add1
     Scheduler( const sal_Char *pDebugName = NULL );
a9add1
     Scheduler( const Scheduler& rScheduler );
a9add1
     virtual ~Scheduler();
a9add1
 
a9add1
-    void SetPriority( SchedulerPriority ePriority );
a9add1
+    void SetPriority(SchedulerPriority ePriority) { mePriority = ePriority; }
a9add1
     SchedulerPriority GetPriority() const { return mePriority; }
a9add1
 
a9add1
     void            SetDebugName( const sal_Char *pDebugName ) { mpDebugName = pDebugName; }
a9add1
@@ -82,13 +86,17 @@ public:
a9add1
     bool            IsActive() const { return mbActive; }
a9add1
     void            SetInActive() { mbActive = false; }
a9add1
 
a9add1
-    Scheduler&          operator=( const Scheduler& rScheduler );
a9add1
+    Scheduler&      operator=( const Scheduler& rScheduler );
a9add1
     static void ImplDeInitScheduler();
a9add1
 
a9add1
     // Process one pending Timer with highhest priority
a9add1
     static void CallbackTaskScheduling( bool ignore );
a9add1
-    /// Process one pending task ahead of time with highhest priority.
a9add1
-    static void ProcessTaskScheduling( bool bTimer );
a9add1
+    /// Calculate minimum timeout - and return its value.
a9add1
+    static sal_uInt64 CalculateMinimumTimeout( bool &bHasActiveIdles );
a9add1
+    /// Process one pending task ahead of time with highest priority.
a9add1
+    static bool       ProcessTaskScheduling( bool bTimerOnly );
a9add1
+    /// Process all events until we are idle
a9add1
+    static void       ProcessEventsToIdle();
a9add1
 };
a9add1
 
a9add1
 #endif // INCLUDED_VCL_SCHEDULER_HXX
a9add1
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
a9add1
index 78f758c..716a987 100644
a9add1
--- a/include/vcl/svapp.hxx
a9add1
+++ b/include/vcl/svapp.hxx
a9add1
@@ -459,8 +459,6 @@ public:
a9add1
 
a9add1
      @see Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static void                 Execute();
a9add1
 
a9add1
@@ -468,8 +466,6 @@ public:
a9add1
 
a9add1
      @see Execute, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static void                 Quit();
a9add1
 
a9add1
@@ -481,8 +477,6 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Yield, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
      */
a9add1
     static void                 Reschedule( bool bAllEvents = false );
a9add1
 
a9add1
@@ -490,8 +484,6 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static void                 Yield();
a9add1
 
a9add1
@@ -499,11 +491,15 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, Yield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static void                 EndYield();
a9add1
 
a9add1
+    /** Acquire SolarMutex after it has been temporarily dropped completely.
a9add1
+
a9add1
+        This will Reschedule() on WNT and just acquire on other platforms.
a9add1
+    */
a9add1
+    static void                 ReAcquireSolarMutex(sal_uLong nReleased);
a9add1
+
a9add1
     /** @brief Get the Solar Mutex for this thread.
a9add1
 
a9add1
      Get the Solar Mutex that prevents other threads from accessing VCL
a9add1
@@ -513,8 +509,6 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, Yield, EndYield,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static comphelper::SolarMutex& GetSolarMutex();
a9add1
 
a9add1
@@ -524,8 +518,6 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
           ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static oslThreadIdentifier  GetMainThreadIdentifier();
a9add1
 
a9add1
@@ -538,8 +530,6 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static sal_uLong            ReleaseSolarMutex();
a9add1
 
a9add1
@@ -550,59 +540,9 @@ public:
a9add1
 
a9add1
      @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
           GetMainThreadIdentifier, ReleaseSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, AddPostYieldListener,
a9add1
-          RemovePostYieldListener
a9add1
     */
a9add1
     static void                 AcquireSolarMutex( sal_uLong nCount );
a9add1
 
a9add1
-    /** @brief Enables "no yield" mode
a9add1
-
a9add1
-     "No yield" mode prevents Yield() from waiting for events.
a9add1
-
a9add1
-     @remarks This was originally implemented in OOo bug 98792 to improve
a9add1
-        Impress slideshows.
a9add1
-
a9add1
-     @see DisableNoYieldMode, Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          DisableNoYield, AddPostYieldListener, RemovePostYieldListener
a9add1
-    */
a9add1
-    static void                 EnableNoYieldMode();
a9add1
-
a9add1
-    /** @brief Disables "no yield" mode
a9add1
-
a9add1
-     "No yield" mode prevents Yield() from waiting for events.
a9add1
-
a9add1
-     @remarks This was originally implemented in OOo bug 98792 to improve
a9add1
-        Impress slideshows.
a9add1
-
a9add1
-     @see EnableNoYieldMode, Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYield, AddPostYieldListener, RemovePostYieldListener
a9add1
-    */
a9add1
-
a9add1
-    static void                 DisableNoYieldMode();
a9add1
-
a9add1
-    /** Add a listener for yield events
a9add1
-
a9add1
-     @param  i_rListener     Listener to add
a9add1
-
a9add1
-     @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          EnableNoYieldMode, DisableNoYieldMode, RemovePostYieldListener
a9add1
-    */
a9add1
-    static void                 AddPostYieldListener( const Link<>& i_rListener );
a9add1
-
a9add1
-    /** Remove listener for yield events
a9add1
-
a9add1
-     @param  i_rListener     Listener to remove
a9add1
-
a9add1
-     @see Execute, Quit, Reschedule, Yield, EndYield, GetSolarMutex,
a9add1
-          GetMainThreadIdentifier, ReleaseSolarMutex, AcquireSolarMutex,
a9add1
-          AddPostYieldListener, EnableNoYieldMode, DisableNoYieldMode
a9add1
-    */
a9add1
-    static void                 RemovePostYieldListener( const Link<>& i_rListener );
a9add1
-
a9add1
-
a9add1
     /** Queries whether the application is in "main", i.e. not yet in
a9add1
         the event loop
a9add1
 
a9add1
@@ -1687,7 +1627,7 @@ public:
a9add1
 
a9add1
     ~SolarMutexReleaser()
a9add1
     {
a9add1
-        Application::AcquireSolarMutex( mnReleased );
a9add1
+        Application::ReAcquireSolarMutex(mnReleased);
a9add1
     }
a9add1
 };
a9add1
 
a9add1
diff --git a/include/vcl/timer.hxx b/include/vcl/timer.hxx
a9add1
index 8835291..d3abf1f 100644
a9add1
--- a/include/vcl/timer.hxx
a9add1
+++ b/include/vcl/timer.hxx
a9add1
@@ -31,11 +31,9 @@ protected:
a9add1
     bool            mbAuto;
a9add1
 
a9add1
     virtual void SetDeletionFlags() SAL_OVERRIDE;
a9add1
-    virtual bool ReadyForSchedule( bool bTimer ) SAL_OVERRIDE;
a9add1
-    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) SAL_OVERRIDE;
a9add1
-
a9add1
-private:
a9add1
-    static void InitSystemTimer();
a9add1
+    virtual bool ReadyForSchedule( bool bTimerOnly, sal_uInt64 nTimeNow ) const SAL_OVERRIDE;
a9add1
+    virtual bool IsIdle() const SAL_OVERRIDE;
a9add1
+    virtual sal_uInt64 UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) const SAL_OVERRIDE;
a9add1
 
a9add1
 public:
a9add1
     Timer( const sal_Char *pDebugName = NULL );
a9add1
@@ -51,7 +49,6 @@ public:
a9add1
     void            Timeout() { Invoke(); }
a9add1
     Timer&          operator=( const Timer& rTimer );
a9add1
     virtual void    Start() SAL_OVERRIDE;
a9add1
-    static void     ImplStartTimer( ImplSVData* pSVData, sal_uInt64 nMS );
a9add1
 };
a9add1
 
a9add1
 /// An auto-timer is a multi-shot timer re-emitting itself at
a9add1
diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx
a9add1
index bf61d37..c1e1064 100644
a9add1
--- a/sd/source/ui/slideshow/slideshowimpl.cxx
a9add1
+++ b/sd/source/ui/slideshow/slideshowimpl.cxx
a9add1
@@ -538,6 +538,8 @@ SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation,
a9add1
         mpOldActiveWindow = mpViewShell->GetActiveWindow();
a9add1
 
a9add1
     maUpdateTimer.SetTimeoutHdl(LINK(this, SlideshowImpl, updateHdl));
a9add1
+    // Priority must not be too high or we'll starve input handling etc.
a9add1
+    maUpdateTimer.SetPriority(SchedulerPriority::REPAINT);
a9add1
 
a9add1
     maDeactivateTimer.SetTimeoutHdl(LINK(this, SlideshowImpl, deactivateHdl));
a9add1
     maDeactivateTimer.SetTimeout( 20 );
a9add1
@@ -746,9 +748,6 @@ void SAL_CALL SlideshowImpl::disposing()
a9add1
 
a9add1
     setActiveXToolbarsVisible( true );
a9add1
 
a9add1
-    Application::DisableNoYieldMode();
a9add1
-    Application::RemovePostYieldListener(LINK(this, SlideshowImpl, PostYieldListener));
a9add1
-
a9add1
     mbDisposed = true;
a9add1
 }
a9add1
 
a9add1
@@ -1789,22 +1788,6 @@ IMPL_LINK_NOARG_TYPED(SlideshowImpl, updateHdl, Timer *, void)
a9add1
     updateSlideShow();
a9add1
 }
a9add1
 
a9add1
-IMPL_LINK_NOARG(SlideshowImpl, PostYieldListener)
a9add1
-{
a9add1
-    // prevent me from deletion when recursing (App::Reschedule does)
a9add1
-    const rtl::Reference<SlideshowImpl> this_(this);
a9add1
-
a9add1
-    Application::DisableNoYieldMode();
a9add1
-    Application::RemovePostYieldListener(LINK(this, SlideshowImpl, PostYieldListener));
a9add1
-    Application::Reschedule(true); // fix for fdo#32861 - process
a9add1
-                                   // *all* outstanding events after
a9add1
-                                   // yield is done.
a9add1
-    if (mbDisposed)
a9add1
-        return 0;
a9add1
-    Application::Reschedule(true);
a9add1
-    return updateSlideShow();
a9add1
-}
a9add1
-
a9add1
 sal_Int32 SlideshowImpl::updateSlideShow()
a9add1
 {
a9add1
     // prevent me from deletion when recursing (App::EnableYieldMode does)
a9add1
@@ -1816,26 +1799,13 @@ sal_Int32 SlideshowImpl::updateSlideShow()
a9add1
 
a9add1
     try
a9add1
     {
a9add1
-        // TODO(Q3): Evaluate under various systems and setups,
a9add1
-        // whether this is really necessary. Under WinXP and Matrox
a9add1
-        // G550, the frame rates were much more steadier with this
a9add1
-        // tweak, although.
a9add1
-
a9add1
-        // currently no solution, because this kills sound (at least on Windows)
a9add1
-
a9add1
         double fUpdate = 0.0;
a9add1
         if( !xShow->update(fUpdate) )
a9add1
             fUpdate = -1.0;
a9add1
 
a9add1
         if (mxShow.is() && (fUpdate >= 0.0))
a9add1
         {
a9add1
-            if (::basegfx::fTools::equalZero(fUpdate))
a9add1
-            {
a9add1
-                // Use post yield listener for short update intervalls.
a9add1
-                Application::EnableNoYieldMode();
a9add1
-                Application::AddPostYieldListener(LINK(this, SlideshowImpl, PostYieldListener));
a9add1
-            }
a9add1
-            else
a9add1
+            if (!::basegfx::fTools::equalZero(fUpdate))
a9add1
             {
a9add1
                 // Avoid busy loop when the previous call to update()
a9add1
                 // returns a small positive number but not 0 (which is
a9add1
@@ -1852,14 +1822,11 @@ sal_Int32 SlideshowImpl::updateSlideShow()
a9add1
                 // too high (only then conversion to milliseconds and long
a9add1
                 // integer may lead to zero value.)
a9add1
                 OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
a9add1
-
a9add1
-                Application::DisableNoYieldMode();
a9add1
-                Application::RemovePostYieldListener(LINK(this, SlideshowImpl, PostYieldListener));
a9add1
-
a9add1
-                // Use a timer for the asynchronous callback.
a9add1
-                maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
a9add1
-                maUpdateTimer.Start();
a9add1
             }
a9add1
+
a9add1
+            // Use our high resolution timers for the asynchronous callback.
a9add1
+            maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
a9add1
+            maUpdateTimer.Start();
a9add1
         }
a9add1
     }
a9add1
     catch( Exception& )
a9add1
diff --git a/sd/source/ui/slideshow/slideshowimpl.hxx b/sd/source/ui/slideshow/slideshowimpl.hxx
a9add1
index 3e8f00f..f75b1b7 100644
a9add1
--- a/sd/source/ui/slideshow/slideshowimpl.hxx
a9add1
+++ b/sd/source/ui/slideshow/slideshowimpl.hxx
a9add1
@@ -275,7 +275,6 @@ private:
a9add1
     void setActiveXToolbarsVisible( bool bVisible );
a9add1
 
a9add1
     DECL_LINK_TYPED(updateHdl, Timer *, void);
a9add1
-    DECL_LINK( PostYieldListener, void* );
a9add1
     DECL_LINK_TYPED(ReadyForNextInputHdl, Timer *, void);
a9add1
     DECL_LINK( endPresentationHdl, void* );
a9add1
     DECL_LINK( ContextMenuSelectHdl, Menu * );
a9add1
@@ -311,7 +310,7 @@ private:
a9add1
     static void setAutoSaveState( bool bOn );
a9add1
     void gotoPreviousSlide (const bool bSkipAllMainSequenceEffects);
a9add1
 
a9add1
-    /** Called by PostYieldListener and updateHdl handlers this method is
a9add1
+    /** Called by our maUpdateTimer's updateHdl handler this method is
a9add1
         responsible to call the slideshow update() method and, depending on
a9add1
         its return value, wait for a certain amount of time before another
a9add1
         call to update() is scheduled.
a9add1
diff --git a/toolkit/source/awt/vclxtoolkit.cxx b/toolkit/source/awt/vclxtoolkit.cxx
a9add1
index ee1f9b8..f11e167 100644
a9add1
--- a/toolkit/source/awt/vclxtoolkit.cxx
a9add1
+++ b/toolkit/source/awt/vclxtoolkit.cxx
a9add1
@@ -1892,7 +1892,7 @@ void SAL_CALL VCLXToolkit::processEventsToIdle()
a9add1
     throw (::com::sun::star::uno::RuntimeException, std::exception)
a9add1
 {
a9add1
     SolarMutexGuard aSolarGuard;
a9add1
-    Scheduler::ProcessTaskScheduling(false);
a9add1
+    Scheduler::ProcessEventsToIdle();
a9add1
 }
a9add1
 
a9add1
 }
a9add1
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
a9add1
index 7c94f66..39dfe25 100644
a9add1
--- a/vcl/headless/svpinst.cxx
a9add1
+++ b/vcl/headless/svpinst.cxx
a9add1
@@ -259,8 +259,10 @@ SalBitmap* SvpSalInstance::CreateSalBitmap()
a9add1
 #endif
a9add1
 }
a9add1
 
a9add1
-void SvpSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
+    (void) nReleased;
a9add1
+    assert(nReleased == 0); // not implemented
a9add1
     // first, check for already queued events.
a9add1
 
a9add1
     // release yield mutex
a9add1
@@ -324,6 +326,9 @@ void SvpSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 
a9add1
         DoReleaseYield(nTimeoutMS);
a9add1
     }
a9add1
+
a9add1
+    return bEvent ? SalYieldResult::EVENT :
a9add1
+                    SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
 void SvpSalInstance::DoReleaseYield( int nTimeoutMS )
a9add1
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
a9add1
index 44795d5..0d11b1d 100644
a9add1
--- a/vcl/inc/headless/svpinst.hxx
a9add1
+++ b/vcl/inc/headless/svpinst.hxx
a9add1
@@ -157,7 +157,7 @@ public:
a9add1
     // wait next event and dispatch
a9add1
     // must returned by UserEvent (SalFrame::PostEvent)
a9add1
     // and timer
a9add1
-    virtual void            Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+    virtual SalYieldResult  DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) SAL_OVERRIDE;
a9add1
     virtual bool            AnyInput( VclInputFlags nType ) SAL_OVERRIDE;
a9add1
 
a9add1
     // may return NULL to disable session management
a9add1
diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h
a9add1
index b2d6133..9df7d02 100644
a9add1
--- a/vcl/inc/osx/salinst.h
a9add1
+++ b/vcl/inc/osx/salinst.h
a9add1
@@ -109,7 +109,7 @@ public:
a9add1
     virtual sal_uLong       ReleaseYieldMutex() SAL_OVERRIDE;
a9add1
     virtual void            AcquireYieldMutex( sal_uLong nCount ) SAL_OVERRIDE;
a9add1
     virtual bool            CheckYieldMutex() SAL_OVERRIDE;
a9add1
-    virtual void            Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+    virtual +SalYieldResult DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) SAL_OVERRIDE;
a9add1
     virtual bool            AnyInput( VclInputFlags nType ) SAL_OVERRIDE;
a9add1
     virtual SalMenu*        CreateMenu( bool bMenuBar, Menu* pVCLMenu ) SAL_OVERRIDE;
a9add1
     virtual void            DestroyMenu( SalMenu* ) SAL_OVERRIDE;
a9add1
diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx
a9add1
index eb53177..f49bb4c 100644
a9add1
--- a/vcl/inc/salinst.hxx
a9add1
+++ b/vcl/inc/salinst.hxx
a9add1
@@ -58,6 +58,8 @@ struct SystemWindowData;
a9add1
 class Menu;
a9add1
 enum class VclInputFlags;
a9add1
 
a9add1
+enum SalYieldResult { EVENT, TIMEOUT };
a9add1
+
a9add1
 class VCL_PLUGIN_PUBLIC SalInstance
a9add1
 {
a9add1
 private:
a9add1
@@ -124,10 +126,13 @@ public:
a9add1
     // return true, if yield mutex is owned by this thread, else false
a9add1
     virtual bool            CheckYieldMutex() = 0;
a9add1
 
a9add1
-    // wait next event and dispatch
a9add1
-    // must returned by UserEvent (SalFrame::PostEvent)
a9add1
-    // and timer
a9add1
-    virtual void            Yield( bool bWait, bool bHandleAllCurrentEvents ) = 0;
a9add1
+    /**
a9add1
+     * Wait for the next event (if @bWait) and dispatch it,
a9add1
+     * includes posted events, and timers.
a9add1
+     * If @bHandleAllCurrentEvents - dispatch multiple posted
a9add1
+     * user events. Returns true if events needed processing.
a9add1
+     */
a9add1
+    virtual SalYieldResult  DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) = 0;
a9add1
     virtual bool            AnyInput( VclInputFlags nType ) = 0;
a9add1
 
a9add1
     // menus
a9add1
diff --git a/vcl/inc/saltimer.hxx b/vcl/inc/saltimer.hxx
a9add1
index 1e1a941..3907ec1 100644
a9add1
--- a/vcl/inc/saltimer.hxx
a9add1
+++ b/vcl/inc/saltimer.hxx
a9add1
@@ -54,6 +54,23 @@ public:
a9add1
     }
a9add1
 };
a9add1
 
a9add1
+class Scheduler;
a9add1
+
a9add1
+// Internal scheduler record holding intrusive linked list pieces
a9add1
+struct ImplSchedulerData
a9add1
+{
a9add1
+    ImplSchedulerData*  mpNext;        // Pointer to the next element in list
a9add1
+    Scheduler*          mpScheduler;   // Pointer to VCL Scheduler instance
a9add1
+    bool                mbDelete;      // Destroy this scheduler?
a9add1
+    bool                mbInScheduler; // Scheduler currently processed?
a9add1
+    sal_uInt64          mnUpdateTime;  // Last Update Time
a9add1
+
a9add1
+    void Invoke();
a9add1
+
a9add1
+    const char *GetDebugName() const;
a9add1
+    static ImplSchedulerData *GetMostImportantTask( bool bTimer );
a9add1
+};
a9add1
+
a9add1
 #endif // INCLUDED_VCL_INC_SALTIMER_HXX
a9add1
 
a9add1
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
a9add1
diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx
a9add1
index 5e3282a..99cb2e3 100644
a9add1
--- a/vcl/inc/svdata.hxx
a9add1
+++ b/vcl/inc/svdata.hxx
a9add1
@@ -125,7 +125,6 @@ struct ImplSVAppData
a9add1
     VclPtr<ImplWheelWindow> mpWheelWindow;                  // WheelWindow
a9add1
     ImplHotKey*             mpFirstHotKey;                  // HotKey-Verwaltung
a9add1
     ImplEventHook*          mpFirstEventHook;               // Event-Hooks
a9add1
-    VclEventListeners2*     mpPostYieldListeners;           // post yield listeners
a9add1
     sal_uInt64              mnLastInputTime;                // GetLastInputTime()
a9add1
     sal_uInt16              mnDispatchLevel;                // DispatchLevel
a9add1
     sal_uInt16              mnModalMode;                    // ModalMode Count
a9add1
@@ -137,8 +136,6 @@ struct ImplSVAppData
a9add1
     bool                    mbInAppExecute;                 // is Application::Execute() on stack
a9add1
     bool                    mbAppQuit;                      // is Application::Quit() called
a9add1
     bool                    mbSettingsInit;                 // true: Settings are initialized
a9add1
-    bool                    mbNoYield;                      // Application::Yield will not wait for events if the queue is empty
a9add1
-                                                            // essentially that makes it the same as Application::Reschedule
a9add1
     Application::DialogCancelMode meDialogCancel;           // true: All Dialog::Execute() calls will be terminated immediately with return false
a9add1
 
a9add1
     /** Controls whether showing any IME status window is toggled on or off.
a9add1
@@ -321,7 +318,6 @@ struct ImplSVData
a9add1
     SalSystem*              mpSalSystem;                    // SalSystem interface
a9add1
     ResMgr*                 mpResMgr;                       // SV-Resource-Manager
a9add1
     sal_uInt64              mnTimerPeriod;                  // current timer period
a9add1
-    sal_uInt32              mnUpdateStack;                  // Scheduler on stack
a9add1
     ImplSVAppData           maAppData;                      // indepen data for class Application
a9add1
     ImplSVGDIData           maGDIData;                      // indepen data for Output classes
a9add1
     ImplSVWinData           maWinData;                      // indepen data for Windows classes
a9add1
diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
a9add1
index 697fece..3a800b3 100644
a9add1
--- a/vcl/inc/unx/gtk/gtkdata.hxx
a9add1
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
a9add1
@@ -115,7 +115,7 @@ public:
a9add1
     static gboolean userEventFn( gpointer data );
a9add1
 
a9add1
     void PostUserEvent();
a9add1
-    void Yield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
+    SalYieldResult Yield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
     inline GdkDisplay *GetGdkDisplay();
a9add1
 
a9add1
     virtual void ErrorTrapPush() SAL_OVERRIDE;
a9add1
diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
a9add1
index 28bca36..189b6900 100644
a9add1
--- a/vcl/inc/unx/gtk/gtkinst.hxx
a9add1
+++ b/vcl/inc/unx/gtk/gtkinst.hxx
a9add1
@@ -80,7 +80,7 @@ public:
a9add1
                                                      const SystemGraphicsData* ) SAL_OVERRIDE;
a9add1
     virtual SalBitmap*          CreateSalBitmap() SAL_OVERRIDE;
a9add1
 
a9add1
-    virtual void                Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+    virtual SalYieldResult                DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) SAL_OVERRIDE;
a9add1
     virtual bool                AnyInput( VclInputFlags nType ) SAL_OVERRIDE;
a9add1
 
a9add1
     virtual GenPspGraphics     *CreatePrintGraphics() SAL_OVERRIDE;
a9add1
diff --git a/vcl/inc/unx/saldisp.hxx b/vcl/inc/unx/saldisp.hxx
a9add1
index a304a4b..776cb64 100644
a9add1
--- a/vcl/inc/unx/saldisp.hxx
a9add1
+++ b/vcl/inc/unx/saldisp.hxx
a9add1
@@ -155,7 +155,7 @@ public:
a9add1
     virtual         ~SalXLib();
a9add1
     virtual void    Init();
a9add1
 
a9add1
-    virtual void    Yield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
+    virtual SalYieldResult Yield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
     virtual void    Wakeup();
a9add1
     virtual void    PostUserEvent();
a9add1
 
a9add1
@@ -382,7 +382,7 @@ public:
a9add1
     virtual ~SalX11Display();
a9add1
 
a9add1
     virtual bool        Dispatch( XEvent *pEvent ) SAL_OVERRIDE;
a9add1
-    virtual void        Yield();
a9add1
+    virtual bool        Yield();
a9add1
     virtual void        PostUserEvent() SAL_OVERRIDE;
a9add1
 
a9add1
     bool                IsEvent();
a9add1
diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h
a9add1
index 381ddda..72939e8 100644
a9add1
--- a/vcl/inc/unx/salinst.h
a9add1
+++ b/vcl/inc/unx/salinst.h
a9add1
@@ -71,7 +71,7 @@ public:
a9add1
     virtual SalBitmap*          CreateSalBitmap() SAL_OVERRIDE;
a9add1
     virtual SalSession*         CreateSalSession() SAL_OVERRIDE;
a9add1
 
a9add1
-    virtual void                Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+    virtual SalYieldResult                DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) SAL_OVERRIDE;
a9add1
     virtual bool                AnyInput( VclInputFlags nType ) SAL_OVERRIDE;
a9add1
 
a9add1
     virtual void*               GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) SAL_OVERRIDE;
a9add1
diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h
a9add1
index 450d07c..0c9c759 100644
a9add1
--- a/vcl/inc/win/salinst.h
a9add1
+++ b/vcl/inc/win/salinst.h
a9add1
@@ -62,7 +62,7 @@ public:
a9add1
     virtual void                AcquireYieldMutex( sal_uIntPtr nCount ) SAL_OVERRIDE;
a9add1
     virtual bool                CheckYieldMutex() SAL_OVERRIDE;
a9add1
 
a9add1
-    virtual void                Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+    virtual SalYieldResult      DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong nReleased) SAL_OVERRIDE;
a9add1
     virtual bool                AnyInput( VclInputFlags nType ) SAL_OVERRIDE;
a9add1
     virtual SalMenu*            CreateMenu( bool bMenuBar, Menu* ) SAL_OVERRIDE;
a9add1
     virtual void                DestroyMenu( SalMenu* ) SAL_OVERRIDE;
a9add1
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
a9add1
index 58a52d5..e20bbdd 100644
a9add1
--- a/vcl/osx/salinst.cxx
a9add1
+++ b/vcl/osx/salinst.cxx
a9add1
@@ -554,8 +554,11 @@ class ReleasePoolHolder
a9add1
     ~ReleasePoolHolder() { [mpPool release]; }
a9add1
 };
a9add1
 
a9add1
-void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
+    (void) nReleased;
a9add1
+    assert(nReleased == 0); // not implemented
a9add1
+
a9add1
     // ensure that the per thread autorelease pool is top level and
a9add1
     // will therefore not be destroyed by cocoa implicitly
a9add1
     SalData::ensureThreadAutoreleasePool();
a9add1
@@ -592,12 +595,13 @@ void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
             osl_setCondition( maWaitingYieldCond );
a9add1
             // return if only one event is asked for
a9add1
             if( ! bHandleAllCurrentEvents )
a9add1
-                return;
a9add1
+                return SalYieldResult::EVENT;
a9add1
         }
a9add1
     }
a9add1
 
a9add1
     // handle cocoa event queue
a9add1
-    // cocoa events mye be only handled in the thread the NSApp was created
a9add1
+    // cocoa events may be only handled in the thread the NSApp was created
a9add1
+    bool bHadEvent = false;
a9add1
     if( isNSAppThread() && mnActivePrintJobs == 0 )
a9add1
     {
a9add1
         // we need to be woken up by a cocoa-event
a9add1
@@ -607,7 +611,6 @@ void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 
a9add1
         // handle available events
a9add1
         NSEvent* pEvent = nil;
a9add1
-        bool bHadEvent = false;
a9add1
         do
a9add1
         {
a9add1
             sal_uLong nCount = ReleaseYieldMutex();
a9add1
@@ -702,6 +705,8 @@ void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
             bInAppEvent = false;
a9add1
         }
a9add1
     }
a9add1
+
a9add1
+    return bHadEvent ? SalYieldResult::EVENT : SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
 bool AquaSalInstance::AnyInput( VclInputFlags nType )
a9add1
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
a9add1
index 144d626..bac8a62 100644
a9add1
--- a/vcl/qa/cppunit/timer.cxx
a9add1
+++ b/vcl/qa/cppunit/timer.cxx
a9add1
@@ -126,7 +126,7 @@ void TimerTest::testIdleMainloop()
a9add1
         // can't test this via Application::Yield since this
a9add1
         // also processes all tasks directly via the scheduler.
a9add1
         pSVData->maAppData.mnDispatchLevel++;
a9add1
-        pSVData->mpDefInst->Yield( true, false );
a9add1
+        pSVData->mpDefInst->DoYield(true, false, 0);
a9add1
         pSVData->maAppData.mnDispatchLevel--;
a9add1
     }
a9add1
     CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered);
a9add1
diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx
a9add1
index 901c44e..8f475de 100644
a9add1
--- a/vcl/source/app/idle.cxx
a9add1
+++ b/vcl/source/app/idle.cxx
a9add1
@@ -18,8 +18,7 @@
a9add1
  */
a9add1
 
a9add1
 #include <vcl/idle.hxx>
a9add1
-#include <vcl/timer.hxx>
a9add1
-#include "svdata.hxx"
a9add1
+#include "saltimer.hxx"
a9add1
 
a9add1
 void Idle::Invoke()
a9add1
 {
a9add1
@@ -45,35 +44,36 @@ Idle::Idle( const Idle& rIdle ) : Scheduler(rIdle)
a9add1
 void Idle::Start()
a9add1
 {
a9add1
     Scheduler::Start();
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    Timer::ImplStartTimer( pSVData, 0 );
a9add1
+    Scheduler::ImplStartTimer(Scheduler::ImmediateTimeoutMs);
a9add1
 }
a9add1
 
a9add1
-bool Idle::ReadyForSchedule( bool bTimer )
a9add1
+bool Idle::ReadyForSchedule( bool bTimerOnly, sal_uInt64 /* nTimeNow */ ) const
a9add1
 {
a9add1
-    // tdf#91727 - We need to re-work this to allow only UI idle handlers
a9add1
-    //             and not timeouts to be processed in some limited scenarios
a9add1
-    (void)bTimer;
a9add1
-    return true; // !bTimer
a9add1
+    // always ready if not only looking for timers.
a9add1
+    return !bTimerOnly;
a9add1
 }
a9add1
 
a9add1
-sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 /* nTime */ )
a9add1
+bool Idle::IsIdle() const
a9add1
+{
a9add1
+    return true;
a9add1
+}
a9add1
+
a9add1
+sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 /* nTime */ ) const
a9add1
 {
a9add1
     switch (mePriority) {
a9add1
     case SchedulerPriority::HIGHEST:
a9add1
     case SchedulerPriority::HIGH:
a9add1
     case SchedulerPriority::RESIZE:
a9add1
     case SchedulerPriority::REPAINT:
a9add1
-        nMinPeriod = 1; // don't wait.
a9add1
+        nMinPeriod = ImmediateTimeoutMs; // don't wait.
a9add1
         break;
a9add1
     default:
a9add1
         // FIXME: tdf#92036 workaround, I should be 1 too - wait 5ms
a9add1
-        if (nMinPeriod > 5)
a9add1
+        if (nMinPeriod < 5)
a9add1
             nMinPeriod = 5;
a9add1
         break;
a9add1
     }
a9add1
     return nMinPeriod;
a9add1
 }
a9add1
 
a9add1
-
a9add1
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
a9add1
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
a9add1
index c3cea78..dd004fb 100644
a9add1
--- a/vcl/source/app/scheduler.cxx
a9add1
+++ b/vcl/source/app/scheduler.cxx
a9add1
@@ -20,10 +20,9 @@
a9add1
 #include <svdata.hxx>
a9add1
 #include <tools/time.hxx>
a9add1
 #include <vcl/scheduler.hxx>
a9add1
-#include <vcl/timer.hxx>
a9add1
 #include <saltimer.hxx>
a9add1
-
a9add1
-#define MAX_TIMER_PERIOD    SAL_MAX_UINT64
a9add1
+#include <svdata.hxx>
a9add1
+#include <salinst.hxx>
a9add1
 
a9add1
 void ImplSchedulerData::Invoke()
a9add1
 {
a9add1
@@ -39,15 +38,17 @@ void ImplSchedulerData::Invoke()
a9add1
     mbInScheduler = false;
a9add1
 }
a9add1
 
a9add1
-ImplSchedulerData *ImplSchedulerData::GetMostImportantTask( bool bTimer )
a9add1
+ImplSchedulerData *ImplSchedulerData::GetMostImportantTask( bool bTimerOnly )
a9add1
 {
a9add1
     ImplSVData*     pSVData = ImplGetSVData();
a9add1
     ImplSchedulerData *pMostUrgent = NULL;
a9add1
 
a9add1
+    sal_uInt64 nTimeNow = tools::Time::GetSystemTicks();
a9add1
     for ( ImplSchedulerData *pSchedulerData = pSVData->mpFirstSchedulerData; pSchedulerData; pSchedulerData = pSchedulerData->mpNext )
a9add1
     {
a9add1
-        if ( !pSchedulerData->mpScheduler || pSchedulerData->mbDelete || pSchedulerData->mnUpdateStack >= pSVData->mnUpdateStack
a9add1
-            || !pSchedulerData->mpScheduler->ReadyForSchedule( bTimer ) || !pSchedulerData->mpScheduler->IsActive())
a9add1
+        if ( !pSchedulerData->mpScheduler || pSchedulerData->mbDelete ||
a9add1
+             !pSchedulerData->mpScheduler->ReadyForSchedule( bTimerOnly, nTimeNow ) ||
a9add1
+             !pSchedulerData->mpScheduler->IsActive())
a9add1
             continue;
a9add1
         if (!pMostUrgent)
a9add1
             pMostUrgent = pSchedulerData;
a9add1
@@ -94,22 +95,88 @@ void Scheduler::ImplDeInitScheduler()
a9add1
         }
a9add1
         while ( pSchedulerData );
a9add1
 
a9add1
-        pSVData->mpFirstSchedulerData   = NULL;
a9add1
-        pSVData->mnTimerPeriod      = 0;
a9add1
+        pSVData->mpFirstSchedulerData = NULL;
a9add1
+        pSVData->mnTimerPeriod = 0;
a9add1
     }
a9add1
 
a9add1
     delete pSVData->mpSalTimer;
a9add1
     pSVData->mpSalTimer = 0;
a9add1
 }
a9add1
 
a9add1
+/**
a9add1
+ * Start a new timer if we need to for @nMS duration.
a9add1
+ *
a9add1
+ * if this is longer than the existing duration we're
a9add1
+ * waiting for, do nothing - unless @bForce - which means
a9add1
+ * to reset the minimum period; used by the scheduled itself.
a9add1
+ */
a9add1
+void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce)
a9add1
+{
a9add1
+    ImplSVData* pSVData = ImplGetSVData();
a9add1
+    InitSystemTimer(pSVData);
a9add1
+
a9add1
+    // only if smaller timeout, to avoid skipping.
a9add1
+    if (bForce || nMS < pSVData->mnTimerPeriod)
a9add1
+    {
a9add1
+        pSVData->mnTimerPeriod = nMS;
a9add1
+        pSVData->mpSalTimer->Start(nMS);
a9add1
+    }
a9add1
+}
a9add1
+
a9add1
+/**
a9add1
+* Initialize the platform specific timer on which all the
a9add1
+* platform independent timers are built
a9add1
+*/
a9add1
+void Scheduler::InitSystemTimer(ImplSVData* pSVData)
a9add1
+{
a9add1
+    assert(pSVData != nullptr);
a9add1
+    if (!pSVData->mpSalTimer)
a9add1
+    {
a9add1
+        pSVData->mnTimerPeriod = MaximumTimeoutMs;
a9add1
+        pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
a9add1
+        pSVData->mpSalTimer->SetCallback(CallbackTaskScheduling);
a9add1
+    }
a9add1
+}
a9add1
+
a9add1
 void Scheduler::CallbackTaskScheduling(bool ignore)
a9add1
 {
a9add1
     // this function is for the saltimer callback
a9add1
     (void)ignore;
a9add1
-    Scheduler::ProcessTaskScheduling( true );
a9add1
+    Scheduler::ProcessTaskScheduling( false );
a9add1
+}
a9add1
+
a9add1
+bool Scheduler::ProcessTaskScheduling( bool bTimerOnly )
a9add1
+{
a9add1
+    ImplSchedulerData* pSchedulerData;
a9add1
+
a9add1
+    // tdf#91727 - NB. bTimerOnly is ultimately not used
a9add1
+    if ((pSchedulerData = ImplSchedulerData::GetMostImportantTask(bTimerOnly)))
a9add1
+    {
a9add1
+        SAL_INFO("vcl.schedule", "Invoke task " << pSchedulerData->GetDebugName());
a9add1
+
a9add1
+        pSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks();
a9add1
+        pSchedulerData->Invoke();
a9add1
+        return true;
a9add1
+    }
a9add1
+    else
a9add1
+        return false;
a9add1
+}
a9add1
+
a9add1
+void Scheduler::ProcessEventsToIdle()
a9add1
+{
a9add1
+    // FIXME: really we should process incoming OS events too ...
a9add1
+    int nSanity = 1000;
a9add1
+    while (Scheduler::ProcessTaskScheduling(false))
a9add1
+    {
a9add1
+        if (nSanity-- < 0)
a9add1
+        {
a9add1
+            SAL_WARN("vcl.schedule", "Unexpected volume of events to process");
a9add1
+            break;
a9add1
+        }
a9add1
+    }
a9add1
 }
a9add1
 
a9add1
-void Scheduler::ProcessTaskScheduling( bool bTimer )
a9add1
+sal_uInt64 Scheduler::CalculateMinimumTimeout( bool &bHasActiveIdles )
a9add1
 {
a9add1
     // process all pending Tasks
a9add1
     // if bTimer True, only handle timer
a9add1
@@ -117,63 +184,70 @@ void Scheduler::ProcessTaskScheduling( bool bTimer )
a9add1
     ImplSchedulerData* pPrevSchedulerData = NULL;
a9add1
     ImplSVData*        pSVData = ImplGetSVData();
a9add1
     sal_uInt64         nTime = tools::Time::GetSystemTicks();
a9add1
-    sal_uInt64         nMinPeriod = MAX_TIMER_PERIOD;
a9add1
-    pSVData->mnUpdateStack++;
a9add1
-
a9add1
-    // tdf#91727 - NB. bTimer is ultimately not used
a9add1
-    if ((pSchedulerData = ImplSchedulerData::GetMostImportantTask(bTimer)))
a9add1
-    {
a9add1
-        pSchedulerData->mnUpdateTime = nTime;
a9add1
-        pSchedulerData->Invoke();
a9add1
-    }
a9add1
+    sal_uInt64         nMinPeriod = MaximumTimeoutMs;
a9add1
 
a9add1
+    SAL_INFO("vcl.schedule", "Calculating minimum timeout:");
a9add1
     pSchedulerData = pSVData->mpFirstSchedulerData;
a9add1
     while ( pSchedulerData )
a9add1
     {
a9add1
-        if( pSchedulerData->mbInScheduler )
a9add1
-        {
a9add1
-            pPrevSchedulerData = pSchedulerData;
a9add1
-            pSchedulerData = pSchedulerData->mpNext;
a9add1
-        }
a9add1
+        ImplSchedulerData *pNext = pSchedulerData->mpNext;
a9add1
+
a9add1
         // Should Task be released from scheduling?
a9add1
-        else if ( pSchedulerData->mbDelete )
a9add1
+        if ( !pSchedulerData->mbInScheduler &&
a9add1
+              pSchedulerData->mbDelete )
a9add1
         {
a9add1
             if ( pPrevSchedulerData )
a9add1
                 pPrevSchedulerData->mpNext = pSchedulerData->mpNext;
a9add1
             else
a9add1
                 pSVData->mpFirstSchedulerData = pSchedulerData->mpNext;
a9add1
             if ( pSchedulerData->mpScheduler )
a9add1
-                pSchedulerData->mpScheduler->mpSchedulerData = NULL;
a9add1
-            ImplSchedulerData* pTempSchedulerData = pSchedulerData;
a9add1
-            pSchedulerData = pSchedulerData->mpNext;
a9add1
-            delete pTempSchedulerData;
a9add1
+                pSchedulerData->mpScheduler->mpSchedulerData = nullptr;
a9add1
+            pNext = pSchedulerData->mpNext;
a9add1
+            delete pSchedulerData;
a9add1
         }
a9add1
         else
a9add1
         {
a9add1
-            pSchedulerData->mnUpdateStack = 0;
a9add1
-            nMinPeriod = pSchedulerData->mpScheduler->UpdateMinPeriod( nMinPeriod, nTime );
a9add1
+            if (!pSchedulerData->mbInScheduler)
a9add1
+            {
a9add1
+                if ( !pSchedulerData->mpScheduler->IsIdle() )
a9add1
+                {
a9add1
+                    sal_uInt64 nOldMinPeriod = nMinPeriod;
a9add1
+                    nMinPeriod = pSchedulerData->mpScheduler->UpdateMinPeriod(
a9add1
+                                                                nOldMinPeriod, nTime );
a9add1
+                    SAL_INFO("vcl.schedule", "Have active timer " <<
a9add1
+                             pSchedulerData->GetDebugName() <<
a9add1
+                             "update min period from " << nOldMinPeriod <<
a9add1
+                             " to " << nMinPeriod);
a9add1
+                }
a9add1
+                else
a9add1
+                {
a9add1
+                    SAL_INFO("vcl.schedule", "Have active idle " <<
a9add1
+                             pSchedulerData->GetDebugName());
a9add1
+                    bHasActiveIdles = true;
a9add1
+                }
a9add1
+            }
a9add1
             pPrevSchedulerData = pSchedulerData;
a9add1
-            pSchedulerData = pSchedulerData->mpNext;
a9add1
         }
a9add1
+        pSchedulerData = pNext;
a9add1
     }
a9add1
 
a9add1
-    // delete clock if no more timers available
a9add1
+    // delete clock if no more timers available,
a9add1
     if ( !pSVData->mpFirstSchedulerData )
a9add1
     {
a9add1
         if ( pSVData->mpSalTimer )
a9add1
             pSVData->mpSalTimer->Stop();
a9add1
-        pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
a9add1
+        nMinPeriod = MaximumTimeoutMs;
a9add1
+        pSVData->mnTimerPeriod = nMinPeriod;
a9add1
+        SAL_INFO("vcl.schedule", "Unusual - no more timers available - stop timer");
a9add1
     }
a9add1
     else
a9add1
     {
a9add1
-        Timer::ImplStartTimer( pSVData, nMinPeriod );
a9add1
+        Scheduler::ImplStartTimer(nMinPeriod, true);
a9add1
+        SAL_INFO("vcl.schedule", "Calculated minimum timeout as " << nMinPeriod << " and " <<
a9add1
+                 (const char *)(bHasActiveIdles ? "has active idles" : "no idles"));
a9add1
     }
a9add1
-    pSVData->mnUpdateStack--;
a9add1
-}
a9add1
 
a9add1
-void Scheduler::SetPriority( SchedulerPriority ePriority )
a9add1
-{
a9add1
-    mePriority = ePriority;
a9add1
+    return nMinPeriod;
a9add1
 }
a9add1
 
a9add1
 void Scheduler::Start()
a9add1
@@ -205,7 +279,6 @@ void Scheduler::Start()
a9add1
     }
a9add1
     mpSchedulerData->mbDelete      = false;
a9add1
     mpSchedulerData->mnUpdateTime  = tools::Time::GetSystemTicks();
a9add1
-    mpSchedulerData->mnUpdateStack = pSVData->mnUpdateStack;
a9add1
 }
a9add1
 
a9add1
 void Scheduler::Stop()
a9add1
@@ -221,7 +294,7 @@ Scheduler& Scheduler::operator=( const Scheduler& rScheduler )
a9add1
     if ( IsActive() )
a9add1
         Stop();
a9add1
 
a9add1
-    mbActive          = false;
a9add1
+    mbActive = false;
a9add1
     mePriority = rScheduler.mePriority;
a9add1
 
a9add1
     if ( rScheduler.IsActive() )
a9add1
@@ -257,3 +330,10 @@ Scheduler::~Scheduler()
a9add1
     }
a9add1
 }
a9add1
 
a9add1
+const char *ImplSchedulerData::GetDebugName() const
a9add1
+{
a9add1
+    return mpScheduler && mpScheduler->GetDebugName() ?
a9add1
+        mpScheduler->GetDebugName() : "unknown";
a9add1
+}
a9add1
+
a9add1
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
a9add1
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
a9add1
index c261a37..302c4a7 100644
a9add1
--- a/vcl/source/app/svapp.cxx
a9add1
+++ b/vcl/source/app/svapp.cxx
a9add1
@@ -338,48 +338,86 @@ void Application::Execute()
a9add1
     pSVData->maAppData.mbInAppExecute = false;
a9add1
 }
a9add1
 
a9add1
-inline void ImplYield( bool i_bWait, bool i_bAllEvents )
a9add1
+inline void ImplYield(bool i_bWait, bool i_bAllEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
     ImplSVData* pSVData = ImplGetSVData();
a9add1
 
a9add1
-    //Process all Tasks
a9add1
-    Scheduler::ProcessTaskScheduling(false);
a9add1
+    SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
a9add1
+             ": " << (i_bAllEvents ? "all events" : "one event") << ": " << nReleased);
a9add1
 
a9add1
+    bool bHasActiveIdles = false;
a9add1
+    sal_uInt64 nMinTimeout = 0;
a9add1
+    if (nReleased == 0) // else thread doesn't have SolarMutex so avoid race
a9add1
+        nMinTimeout = Scheduler::CalculateMinimumTimeout(bHasActiveIdles);
a9add1
+
a9add1
+    // FIXME: should use returned value as param to DoYield
a9add1
+    (void)nMinTimeout;
a9add1
+
a9add1
+    // If we have idles, don't wait for the timeout; check for events
a9add1
+    // and come back as quick as possible.
a9add1
+    if (bHasActiveIdles)
a9add1
+        i_bWait = false;
a9add1
+
a9add1
+    // TODO: there's a data race here on WNT only because ImplYield may be
a9add1
+    // called without SolarMutex; if we can get rid of LazyDelete (with VclPtr)
a9add1
+    // then the only remaining use of mnDispatchLevel is in OSX specific code
a9add1
+    // so that would effectively eliminate the race on WNT
a9add1
     pSVData->maAppData.mnDispatchLevel++;
a9add1
+
a9add1
     // do not wait for events if application was already quit; in that
a9add1
     // case only dispatch events already available
a9add1
     // do not wait for events either if the app decided that it is too busy for timers
a9add1
     // (feature added for the slideshow)
a9add1
-    pSVData->mpDefInst->Yield( i_bWait && !pSVData->maAppData.mbAppQuit && !pSVData->maAppData.mbNoYield, i_bAllEvents );
a9add1
+    SalYieldResult eResult =
a9add1
+        pSVData->mpDefInst->DoYield(
a9add1
+            i_bWait && !pSVData->maAppData.mbAppQuit,
a9add1
+            i_bAllEvents, nReleased);
a9add1
+
a9add1
+    SAL_INFO("vcl.schedule", "DoYield with " << (bHasActiveIdles ? "active idles" : "no ides") <<
a9add1
+             " returns: " << (eResult == SalYieldResult::EVENT ? "processed event" : "timeout"));
a9add1
+
a9add1
     pSVData->maAppData.mnDispatchLevel--;
a9add1
 
a9add1
     DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
a9add1
 
a9add1
+    // Process all Tasks
a9add1
+    Scheduler::ProcessTaskScheduling(eResult == SalYieldResult::EVENT);
a9add1
+
a9add1
     // flush lazy deleted objects
a9add1
     if( pSVData->maAppData.mnDispatchLevel == 0 )
a9add1
         vcl::LazyDelete::flush();
a9add1
 
a9add1
-    // the system timer events will not necessarily come in non waiting mode
a9add1
-    // e.g. on OS X; need to trigger timer checks manually
a9add1
-    if( pSVData->maAppData.mbNoYield )
a9add1
-    {
a9add1
-        //Process all timers
a9add1
-        Scheduler::ProcessTaskScheduling(true);
a9add1
-    }
a9add1
-
a9add1
-    // call post yield listeners
a9add1
-    if( pSVData->maAppData.mpPostYieldListeners )
a9add1
-        pSVData->maAppData.mpPostYieldListeners->callListeners( NULL );
a9add1
+    SAL_INFO("vcl.schedule", "Leave ImplYield");
a9add1
 }
a9add1
 
a9add1
 void Application::Reschedule( bool i_bAllEvents )
a9add1
 {
a9add1
-    ImplYield( false, i_bAllEvents );
a9add1
+    ImplYield(false, i_bAllEvents, 0);
a9add1
 }
a9add1
 
a9add1
 void Application::Yield()
a9add1
 {
a9add1
-    ImplYield( true, false );
a9add1
+    ImplYield(true, false, 0);
a9add1
+}
a9add1
+
a9add1
+void Application::ReAcquireSolarMutex(sal_uLong const nReleased)
a9add1
+{
a9add1
+    // 0 would mean that events/timers will be handled without locking
a9add1
+    // SolarMutex (racy)
a9add1
+    assert(nReleased != 0);
a9add1
+#ifdef WNT
a9add1
+    if (ImplGetSVData()->mbDeInit) // do not Yield in DeInitVCL
a9add1
+        AcquireSolarMutex(nReleased);
a9add1
+    else
a9add1
+        ImplYield(false, false, nReleased);
a9add1
+#else
a9add1
+    // a) Yield is not needed on non-WNT platforms
a9add1
+    // b) some Yield implementations for X11 (e.g. kde4) make it non-obvious
a9add1
+    //    how to use nReleased
a9add1
+    // c) would require a review of what all Yield implementations do
a9add1
+    //    currently _before_ releasing SolarMutex that would run without lock
a9add1
+    AcquireSolarMutex(nReleased);
a9add1
+#endif
a9add1
 }
a9add1
 
a9add1
 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg )
a9add1
@@ -965,33 +1003,6 @@ void Application::RemoveIdleHdl( const Link<>& rLink )
a9add1
         pSVData->maAppData.mpIdleMgr->RemoveIdleHdl( rLink );
a9add1
 }
a9add1
 
a9add1
-void Application::EnableNoYieldMode()
a9add1
-{
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    pSVData->maAppData.mbNoYield = true;
a9add1
-}
a9add1
-
a9add1
-void Application::DisableNoYieldMode()
a9add1
-{
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    pSVData->maAppData.mbNoYield = false;
a9add1
-}
a9add1
-
a9add1
-void Application::AddPostYieldListener( const Link<>& i_rListener )
a9add1
-{
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    if( ! pSVData->maAppData.mpPostYieldListeners )
a9add1
-        pSVData->maAppData.mpPostYieldListeners = new VclEventListeners2();
a9add1
-    pSVData->maAppData.mpPostYieldListeners->addListener( i_rListener );
a9add1
-}
a9add1
-
a9add1
-void Application::RemovePostYieldListener( const Link<>& i_rListener )
a9add1
-{
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    if( pSVData->maAppData.mpPostYieldListeners )
a9add1
-        pSVData->maAppData.mpPostYieldListeners->removeListener( i_rListener );
a9add1
-}
a9add1
-
a9add1
 WorkWindow* Application::GetAppWindow()
a9add1
 {
a9add1
     return ImplGetSVData()->maWinData.mpAppWin;
a9add1
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
a9add1
index 72881a6..23757e8 100644
a9add1
--- a/vcl/source/app/svmain.cxx
a9add1
+++ b/vcl/source/app/svmain.cxx
a9add1
@@ -508,11 +508,6 @@ void DeInitVCL()
a9add1
         delete pSVData->maAppData.mpKeyListeners;
a9add1
         pSVData->maAppData.mpKeyListeners = NULL;
a9add1
     }
a9add1
-    if ( pSVData->maAppData.mpPostYieldListeners )
a9add1
-    {
a9add1
-        delete pSVData->maAppData.mpPostYieldListeners;
a9add1
-        pSVData->maAppData.mpPostYieldListeners = NULL;
a9add1
-    }
a9add1
 
a9add1
     if ( pSVData->maAppData.mpFirstHotKey )
a9add1
         ImplFreeHotKeyData();
a9add1
diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx
a9add1
index 7d92283..1766d7f 100644
a9add1
--- a/vcl/source/app/timer.cxx
a9add1
+++ b/vcl/source/app/timer.cxx
a9add1
@@ -19,46 +19,30 @@
a9add1
 
a9add1
 #include <tools/time.hxx>
a9add1
 #include <vcl/timer.hxx>
a9add1
-#include <saltimer.hxx>
a9add1
-#include <svdata.hxx>
a9add1
-#include <salinst.hxx>
a9add1
+#include "saltimer.hxx"
a9add1
 
a9add1
-#define MAX_TIMER_PERIOD   SAL_MAX_UINT64
a9add1
-
a9add1
-void Timer::ImplStartTimer( ImplSVData* pSVData, sal_uInt64 nMS )
a9add1
+void Timer::SetDeletionFlags()
a9add1
 {
a9add1
-    InitSystemTimer();
a9add1
-
a9add1
-    if ( !nMS )
a9add1
-        nMS = 1;
a9add1
-
a9add1
-    // Assume underlying timers are recurring timers, if same period - just wait.
a9add1
-    if ( nMS != pSVData->mnTimerPeriod )
a9add1
+    // If no AutoTimer, then stop.
a9add1
+    if ( !mbAuto )
a9add1
     {
a9add1
-        pSVData->mnTimerPeriod = nMS;
a9add1
-        pSVData->mpSalTimer->Start( nMS );
a9add1
+        mpSchedulerData->mbDelete = true;
a9add1
+        mbActive = false;
a9add1
     }
a9add1
 }
a9add1
 
a9add1
-void Timer::SetDeletionFlags()
a9add1
+bool Timer::ReadyForSchedule( bool /* bTimerOnly */, sal_uInt64 nTimeNow ) const
a9add1
 {
a9add1
-        // if no AutoTimer than stop
a9add1
-        if ( !mbAuto )
a9add1
-        {
a9add1
-            mpSchedulerData->mbDelete = true;
a9add1
-            mbActive = false;
a9add1
-        }
a9add1
+    return (mpSchedulerData->mnUpdateTime + mnTimeout) <= nTimeNow;
a9add1
 }
a9add1
 
a9add1
-bool Timer::ReadyForSchedule( bool bTimer )
a9add1
+bool Timer::IsIdle() const
a9add1
 {
a9add1
-    (void)bTimer;
a9add1
-    return (mpSchedulerData->mnUpdateTime + mnTimeout) <= tools::Time::GetSystemTicks();
a9add1
+    return false;
a9add1
 }
a9add1
 
a9add1
-sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime )
a9add1
+sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime ) const
a9add1
 {
a9add1
-    sal_uInt64 nNewTime = tools::Time::GetSystemTicks();
a9add1
     sal_uInt64 nDeltaTime;
a9add1
     //determine smallest time slot
a9add1
     if( mpSchedulerData->mnUpdateTime == nTime )
a9add1
@@ -70,11 +54,11 @@ sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime )
a9add1
     else
a9add1
     {
a9add1
         nDeltaTime = mpSchedulerData->mnUpdateTime + mnTimeout;
a9add1
-        if( nDeltaTime < nNewTime )
a9add1
-            nMinPeriod = 1;
a9add1
+        if( nDeltaTime < nTime )
a9add1
+            nMinPeriod = ImmediateTimeoutMs;
a9add1
         else
a9add1
         {
a9add1
-            nDeltaTime -= nNewTime;
a9add1
+            nDeltaTime -= nTime;
a9add1
             if( nDeltaTime < nMinPeriod )
a9add1
                 nMinPeriod = nDeltaTime;
a9add1
         }
a9add1
@@ -83,32 +67,19 @@ sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nMinPeriod, sal_uInt64 nTime )
a9add1
     return nMinPeriod;
a9add1
 }
a9add1
 
a9add1
-/**
a9add1
- * Initialize the platform specific timer on which all the
a9add1
- * platform independent timers are built
a9add1
- */
a9add1
-void Timer::InitSystemTimer()
a9add1
-{
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    if( ! pSVData->mpSalTimer )
a9add1
-    {
a9add1
-        pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
a9add1
-        pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
a9add1
-        pSVData->mpSalTimer->SetCallback( CallbackTaskScheduling );
a9add1
-    }
a9add1
-}
a9add1
-
a9add1
-Timer::Timer(const sal_Char *pDebugName) : Scheduler(pDebugName)
a9add1
+Timer::Timer(const sal_Char *pDebugName) :
a9add1
+    Scheduler(pDebugName),
a9add1
+    mnTimeout(ImmediateTimeoutMs),
a9add1
+    mbAuto(false)
a9add1
 {
a9add1
-    mnTimeout = 1;
a9add1
-    mbAuto = false;
a9add1
     mePriority = SchedulerPriority::HIGHEST;
a9add1
 }
a9add1
 
a9add1
-Timer::Timer( const Timer& rTimer ) : Scheduler(rTimer)
a9add1
+Timer::Timer( const Timer& rTimer ) :
a9add1
+    Scheduler(rTimer),
a9add1
+    mnTimeout(rTimer.mnTimeout),
a9add1
+    mbAuto(rTimer.mbAuto)
a9add1
 {
a9add1
-    mnTimeout = rTimer.mnTimeout;
a9add1
-    mbAuto = rTimer.mbAuto;
a9add1
     maTimeoutHdl = rTimer.maTimeoutHdl;
a9add1
 }
a9add1
 
a9add1
@@ -120,21 +91,16 @@ void Timer::Invoke()
a9add1
 void Timer::Start()
a9add1
 {
a9add1
     Scheduler::Start();
a9add1
-
a9add1
-    ImplSVData* pSVData = ImplGetSVData();
a9add1
-    if ( mnTimeout < pSVData->mnTimerPeriod )
a9add1
-        Timer::ImplStartTimer( pSVData, mnTimeout );
a9add1
+    Scheduler::ImplStartTimer(mnTimeout);
a9add1
 }
a9add1
 
a9add1
 void Timer::SetTimeout( sal_uInt64 nNewTimeout )
a9add1
 {
a9add1
     mnTimeout = nNewTimeout;
a9add1
-    // if timer is active then renew clock
a9add1
+    // If timer is active, then renew clock.
a9add1
     if ( mbActive )
a9add1
     {
a9add1
-        ImplSVData* pSVData = ImplGetSVData();
a9add1
-        if ( !pSVData->mnUpdateStack && (mnTimeout < pSVData->mnTimerPeriod) )
a9add1
-            Timer::ImplStartTimer( pSVData, mnTimeout );
a9add1
+        Scheduler::ImplStartTimer(mnTimeout);
a9add1
     }
a9add1
 }
a9add1
 
a9add1
diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx
a9add1
index b2212a4..ac872b7 100644
a9add1
--- a/vcl/unx/generic/app/saldata.cxx
a9add1
+++ b/vcl/unx/generic/app/saldata.cxx
a9add1
@@ -619,7 +619,8 @@ bool SalXLib::CheckTimeout( bool bExecuteTimers )
a9add1
     return bRet;
a9add1
 }
a9add1
 
a9add1
-void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult
a9add1
+SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 {
a9add1
     blockIdleTimeout = !bWait;
a9add1
     // check for timeouts here if you want to make screenshots
a9add1
@@ -642,7 +643,7 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
                 if( ! bHandleAllCurrentEvents )
a9add1
                 {
a9add1
                     blockIdleTimeout = false;
a9add1
-                    return;
a9add1
+                    return SalYieldResult::EVENT;
a9add1
                 }
a9add1
             }
a9add1
         }
a9add1
@@ -657,6 +658,8 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
     timeval  Timeout      = noyield__;
a9add1
     timeval *pTimeout     = &Timeout;
a9add1
 
a9add1
+    bool bHandledEvent = false;
a9add1
+
a9add1
     if (bWait)
a9add1
     {
a9add1
         pTimeout = 0;
a9add1
@@ -717,7 +720,7 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
         if (nFound == 0)
a9add1
         {
a9add1
             blockIdleTimeout = false;
a9add1
-            return;
a9add1
+            return SalYieldResult::TIMEOUT;
a9add1
         }
a9add1
 
a9add1
         for ( int nFD = 0; nFD < nFDs_; nFD++ )
a9add1
@@ -736,6 +739,7 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
                     for( int i = 0; pEntry->IsEventQueued() && i < nMaxEvents; i++ )
a9add1
                     {
a9add1
                         pEntry->HandleNextEvent();
a9add1
+                        bHandledEvent = true;
a9add1
                         // if a recursive call has done the job
a9add1
                         // so abort here
a9add1
                     }
a9add1
@@ -745,6 +749,9 @@ void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
         }
a9add1
     }
a9add1
     blockIdleTimeout = false;
a9add1
+
a9add1
+    return bHandledEvent ? SalYieldResult::EVENT
a9add1
+                         : SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
 void SalXLib::Wakeup()
a9add1
diff --git a/vcl/unx/generic/app/saldisp.cxx b/vcl/unx/generic/app/saldisp.cxx
a9add1
index ff71bc6..c039ee2 100644
a9add1
--- a/vcl/unx/generic/app/saldisp.cxx
a9add1
+++ b/vcl/unx/generic/app/saldisp.cxx
a9add1
@@ -1878,10 +1878,10 @@ bool SalX11Display::IsEvent()
a9add1
     return false;
a9add1
 }
a9add1
 
a9add1
-void SalX11Display::Yield()
a9add1
+bool SalX11Display::Yield()
a9add1
 {
a9add1
     if( DispatchInternalEvent() )
a9add1
-        return;
a9add1
+        return true;
a9add1
 
a9add1
     XEvent aEvent;
a9add1
     DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
a9add1
@@ -1890,7 +1890,8 @@ void SalX11Display::Yield()
a9add1
 
a9add1
     XNextEvent( pDisp_, &aEvent );
a9add1
 
a9add1
-    Dispatch( &aEvent );
a9add1
+    // FIXME: under-convinced by Dispatch boolean return value vs. salframe.
a9add1
+    bool bProcessedEvent = Dispatch( &aEvent );
a9add1
 
a9add1
 #ifdef DBG_UTIL
a9add1
     if( GetX11SalData()->HasXErrorOccurred() )
a9add1
@@ -1900,6 +1901,8 @@ void SalX11Display::Yield()
a9add1
     }
a9add1
 #endif
a9add1
     GetX11SalData()->ResetXErrorOccurred();
a9add1
+
a9add1
+    return bProcessedEvent;
a9add1
 }
a9add1
 
a9add1
 bool SalX11Display::Dispatch( XEvent *pEvent )
a9add1
diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx
a9add1
index 9c00f6d..7ac0789 100644
a9add1
--- a/vcl/unx/generic/app/salinst.cxx
a9add1
+++ b/vcl/unx/generic/app/salinst.cxx
a9add1
@@ -151,9 +151,11 @@ bool X11SalInstance::AnyInput(VclInputFlags nType)
a9add1
     return bRet;
a9add1
 }
a9add1
 
a9add1
-void X11SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult X11SalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
-    mpXLib->Yield( bWait, bHandleAllCurrentEvents );
a9add1
+    (void) nReleased;
a9add1
+    assert(nReleased == 0); // not implemented
a9add1
+    return mpXLib->Yield( bWait, bHandleAllCurrentEvents );
a9add1
 }
a9add1
 
a9add1
 void* X11SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType,
a9add1
diff --git a/vcl/unx/gtk/a11y/atkwrapper.cxx b/vcl/unx/gtk/a11y/atkwrapper.cxx
a9add1
index 30cfa9c..006df49 100644
a9add1
--- a/vcl/unx/gtk/a11y/atkwrapper.cxx
a9add1
+++ b/vcl/unx/gtk/a11y/atkwrapper.cxx
a9add1
@@ -872,7 +872,7 @@ atk_object_wrapper_new( const ::com::sun::star::uno::Reference< ::com::sun::star
a9add1
             uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
a9add1
             if( xBroadcaster.is() )
a9add1
                 xBroadcaster->addAccessibleEventListener( static_cast< accessibility::XAccessibleEventListener * > ( new AtkListener(pWrap) ) );
a9add1
-        else
a9add1
+            else
a9add1
                 OSL_ASSERT( false );
a9add1
         }
a9add1
 
a9add1
diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx
a9add1
index 2d8e26c..b59b962 100644
a9add1
--- a/vcl/unx/gtk/app/gtkdata.cxx
a9add1
+++ b/vcl/unx/gtk/app/gtkdata.cxx
a9add1
@@ -566,9 +566,11 @@ void GtkData::Dispose()
a9add1
     deInitNWF();
a9add1
 }
a9add1
 
a9add1
-void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+/// Allows events to be processed, returns true if we processed an event.
a9add1
+SalYieldResult GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 {
a9add1
     blockIdleTimeout = !bWait;
a9add1
+
a9add1
     /* #i33212# only enter g_main_context_iteration in one thread at any one
a9add1
      * time, else one of them potentially will never end as long as there is
a9add1
      * another thread in there. Having only one yieldin thread actually dispatch
a9add1
@@ -584,7 +586,7 @@ void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
         else if( ! bWait )
a9add1
         {
a9add1
             blockIdleTimeout = false;
a9add1
-            return; // someone else is waiting already, return
a9add1
+            return SalYieldResult::TIMEOUT; // someone else is waiting already, return
a9add1
         }
a9add1
 
a9add1
         if( bDispatchThread )
a9add1
@@ -618,6 +620,9 @@ void GtkData::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
             osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
a9add1
     }
a9add1
     blockIdleTimeout = false;
a9add1
+
a9add1
+    return bWasEvent ? SalYieldResult::EVENT
a9add1
+                     : SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
 void GtkData::Init()
a9add1
@@ -885,6 +890,9 @@ create_sal_gtk_timeout( GtkSalTimer *pTimer )
a9add1
                          /* unused dummy */ g_idle_remove_by_data,
a9add1
                          NULL, NULL );
a9add1
   g_source_attach( pSource, g_main_context_default() );
a9add1
+#ifdef DBG_UTIL
a9add1
+  g_source_set_name( pSource, "VCL timeout source" );
a9add1
+#endif
a9add1
 
a9add1
   sal_gtk_timeout_defer( pTSource );
a9add1
 
a9add1
@@ -917,6 +925,8 @@ bool GtkSalTimer::Expired()
a9add1
 
a9add1
 void GtkSalTimer::Start( sal_uLong nMS )
a9add1
 {
a9add1
+    // glib is not 64bit safe in this regard.
a9add1
+    assert( nMS <= G_MAXINT );
a9add1
     m_nTimeoutMS = nMS; // for restarting
a9add1
     Stop(); // FIXME: ideally re-use an existing m_pTimeout
a9add1
     m_pTimeout = create_sal_gtk_timeout( this );
a9add1
diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx
a9add1
index 601fd21..9242b88 100644
a9add1
--- a/vcl/unx/gtk/app/gtkinst.cxx
a9add1
+++ b/vcl/unx/gtk/app/gtkinst.cxx
a9add1
@@ -401,10 +401,12 @@ void GtkInstance::RemoveTimer (SalTimer *pTimer)
a9add1
         m_aTimers.erase( it );
a9add1
 }
a9add1
 
a9add1
-void GtkInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
+    (void) nReleased;
a9add1
+    assert(nReleased == 0); // not implemented
a9add1
     EnsureInit();
a9add1
-    GetGtkSalData()->Yield( bWait, bHandleAllCurrentEvents );
a9add1
+    return GetGtkSalData()->Yield( bWait, bHandleAllCurrentEvents );
a9add1
 }
a9add1
 
a9add1
 bool GtkInstance::IsTimerExpired()
a9add1
diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx
a9add1
index 06e7b6d..42f8ebc 100644
a9add1
--- a/vcl/unx/kde4/KDESalDisplay.cxx
a9add1
+++ b/vcl/unx/kde4/KDESalDisplay.cxx
a9add1
@@ -46,14 +46,14 @@ SalKDEDisplay::~SalKDEDisplay()
a9add1
     pDisp_ = NULL;
a9add1
 }
a9add1
 
a9add1
-void SalKDEDisplay::Yield()
a9add1
+bool SalKDEDisplay::Yield()
a9add1
 {
a9add1
     if( DispatchInternalEvent() )
a9add1
-        return;
a9add1
+        return true;
a9add1
 
a9add1
     // Prevent blocking from Drag'n'Drop events, which may have already have processed the event
a9add1
     if (XEventsQueued( pDisp_, QueuedAfterReading ) == 0)
a9add1
-        return;
a9add1
+        return false;
a9add1
 
a9add1
     DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
a9add1
                 osl::Thread::getCurrentIdentifier(),
a9add1
@@ -62,8 +62,9 @@ void SalKDEDisplay::Yield()
a9add1
     XEvent event;
a9add1
     XNextEvent( pDisp_, &event );
a9add1
     if( checkDirectInputEvent( &event ))
a9add1
-        return;
a9add1
+        return true;
a9add1
     qApp->x11ProcessEvent( &event );
a9add1
+    return true;
a9add1
 }
a9add1
 
a9add1
 // HACK: When using Qt event loop, input methods (japanese, etc.) will get broken because
a9add1
diff --git a/vcl/unx/kde4/KDESalDisplay.hxx b/vcl/unx/kde4/KDESalDisplay.hxx
a9add1
index f4a4146..3e027fd 100644
a9add1
--- a/vcl/unx/kde4/KDESalDisplay.hxx
a9add1
+++ b/vcl/unx/kde4/KDESalDisplay.hxx
a9add1
@@ -27,7 +27,7 @@ class SalKDEDisplay : public SalX11Display
a9add1
         SalKDEDisplay( Display* pDisp );
a9add1
         virtual ~SalKDEDisplay();
a9add1
         static SalKDEDisplay* self();
a9add1
-        virtual void Yield() SAL_OVERRIDE;
a9add1
+        virtual bool Yield() SAL_OVERRIDE;
a9add1
         bool checkDirectInputEvent( XEvent* ev );
a9add1
     private:
a9add1
         Atom xim_protocol;
a9add1
diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
a9add1
index 3101d37..c758e18 100644
a9add1
--- a/vcl/unx/kde4/KDEXLib.cxx
a9add1
+++ b/vcl/unx/kde4/KDEXLib.cxx
a9add1
@@ -281,22 +281,25 @@ void KDEXLib::socketNotifierActivated( int fd )
a9add1
     sdata.handle( fd, sdata.data );
a9add1
 }
a9add1
 
a9add1
-void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 {
a9add1
     if( !m_isGlibEventLoopType )
a9add1
     {
a9add1
+        bool wasEvent = false;
a9add1
         if( qApp->thread() == QThread::currentThread())
a9add1
         {
a9add1
             // even if we use the LO event loop, still process Qt's events,
a9add1
             // otherwise they can remain unhandled for quite a long while
a9add1
-            processYield( false, bHandleAllCurrentEvents );
a9add1
+            wasEvent = processYield( false, bHandleAllCurrentEvents );
a9add1
         }
a9add1
-        return SalXLib::Yield( bWait, bHandleAllCurrentEvents );
a9add1
+        SalYieldResult aResult = SalXLib::Yield(bWait, bHandleAllCurrentEvents);
a9add1
+        return (aResult == SalYieldResult::EVENT || wasEvent) ?
a9add1
+            SalYieldResult::EVENT : SalYieldResult::TIMEOUT;
a9add1
     }
a9add1
     // if we are the main thread (which is where the event processing is done),
a9add1
     // good, just do it
a9add1
     if( qApp->thread() == QThread::currentThread())
a9add1
-        processYield( bWait, bHandleAllCurrentEvents );
a9add1
+        return processYield( bWait, bHandleAllCurrentEvents );
a9add1
     else
a9add1
     {
a9add1
         // we were called from another thread;
a9add1
@@ -305,10 +308,11 @@ void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
         // temporarily do it while checking for new events)
a9add1
         SalYieldMutexReleaser aReleaser;
a9add1
         Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
a9add1
+        return SalYieldResult::TIMEOUT;
a9add1
     }
a9add1
 }
a9add1
 
a9add1
-void KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 {
a9add1
     blockIdleTimeout = !bWait;
a9add1
     QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread());
a9add1
@@ -324,6 +328,8 @@ void KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
     if( bWait && !wasEvent )
a9add1
         dispatcher->processEvents( QEventLoop::WaitForMoreEvents );
a9add1
     blockIdleTimeout = false;
a9add1
+    return wasEvent ? SalYieldResult::EVENT
a9add1
+                    : SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
 void KDEXLib::StartTimer( sal_uLong nMS )
a9add1
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
a9add1
index 0a1aec3..7e432e5 100644
a9add1
--- a/vcl/unx/kde4/KDEXLib.hxx
a9add1
+++ b/vcl/unx/kde4/KDEXLib.hxx
a9add1
@@ -65,7 +65,7 @@ class KDEXLib : public QObject, public SalXLib
a9add1
         void userEventActivated();
a9add1
         void startTimeoutTimer();
a9add1
         void startUserEventTimer();
a9add1
-        void processYield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
+        SalYieldResult processYield( bool bWait, bool bHandleAllCurrentEvents );
a9add1
     Q_SIGNALS:
a9add1
         void startTimeoutTimerSignal();
a9add1
         void startUserEventTimerSignal();
a9add1
@@ -80,7 +80,7 @@ class KDEXLib : public QObject, public SalXLib
a9add1
         virtual ~KDEXLib();
a9add1
 
a9add1
         virtual void Init() SAL_OVERRIDE;
a9add1
-        virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
+        virtual SalYieldResult Yield( bool bWait, bool bHandleAllCurrentEvents ) SAL_OVERRIDE;
a9add1
         virtual void Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle ) SAL_OVERRIDE;
a9add1
         virtual void Remove( int fd ) SAL_OVERRIDE;
a9add1
         virtual void StartTimer( sal_uLong nMS ) SAL_OVERRIDE;
a9add1
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx
a9add1
index 1c21246..d61060f 100644
a9add1
--- a/vcl/win/source/app/salinst.cxx
a9add1
+++ b/vcl/win/source/app/salinst.cxx
a9add1
@@ -602,7 +602,8 @@ static void ImplSalDispatchMessage( MSG* pMsg )
a9add1
         ImplSalPostDispatchMsg( pMsg, lResult );
a9add1
 }
a9add1
 
a9add1
-void ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult
a9add1
+ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
 {
a9add1
     MSG aMsg;
a9add1
     bool bWasMsg = false, bOneEvent = false;
a9add1
@@ -629,15 +630,22 @@ void ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
             ImplSalDispatchMessage( &aMsg );
a9add1
         }
a9add1
     }
a9add1
+    return bWasMsg ? SalYieldResult::EVENT :
a9add1
+                     SalYieldResult::TIMEOUT;
a9add1
 }
a9add1
 
a9add1
-void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
+SalYieldResult WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
a9add1
 {
a9add1
+    SalYieldResult eDidWork = SalYieldResult::TIMEOUT;
a9add1
+    // NOTE: if nReleased != 0 this will be called without SolarMutex
a9add1
+    //       so don't do anything dangerous before releasing it here
a9add1
     SalYieldMutex*  pYieldMutex = mpSalYieldMutex;
a9add1
     SalData*        pSalData = GetSalData();
a9add1
     DWORD           nCurThreadId = GetCurrentThreadId();
a9add1
-    sal_uLong           nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
a9add1
-    sal_uLong           n = nCount;
a9add1
+    sal_uLong const nCount = (nReleased != 0)
a9add1
+                                ? nReleased
a9add1
+                                : pYieldMutex->GetAcquireCount(nCurThreadId);
a9add1
+    sal_uLong       n = (nReleased != 0) ? 0 : nCount;
a9add1
     while ( n )
a9add1
     {
a9add1
         pYieldMutex->release();
a9add1
@@ -669,7 +677,7 @@ void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
     }
a9add1
     else
a9add1
     {
a9add1
-        ImplSalYield( bWait, bHandleAllCurrentEvents );
a9add1
+        eDidWork = ImplSalYield( bWait, bHandleAllCurrentEvents );
a9add1
 
a9add1
         n = nCount;
a9add1
         while ( n )
a9add1
@@ -678,6 +686,7 @@ void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
a9add1
             n--;
a9add1
         }
a9add1
     }
a9add1
+    return eDidWork;
a9add1
 }
a9add1
 
a9add1
 LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
a9add1
-- 
a9add1
2.5.0
a9add1