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

Jan-Marek Glogowski glogow at fbihome.de
Fri Oct 13 14:49:26 UTC 2017


 vcl/inc/win/saltimer.h  |    6 +
 vcl/win/app/salinst.cxx |  175 +++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 150 insertions(+), 31 deletions(-)

New commits:
commit 3bf6c97029d26ddf20007c47ca6b68e5cc52d846
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Oct 12 10:20:17 2017 +0200

    tdf#112975 WIN correctly handle VclInputFlags::OTHER
    
    On Windows we can just check the message queue for existing
    messages. But VclInputFlags::OTHER is used to check for any
    messages, which can't be explicitly checked.
    
    In the case of checking for VclInputFlags::OTHER while
    excluding an other message type, we have to make multiple
    PeekMessage calls and exclude all non-checked message ids.
    
    Change-Id: I1cedd4b76444769842c74228fc547f0d924f8b60
    Reviewed-on: https://gerrit.libreoffice.org/43337
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Jan-Marek Glogowski <glogow at fbihome.de>

diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h
index 37976bbfaf8b..68973e1cadc3 100644
--- a/vcl/inc/win/saltimer.h
+++ b/vcl/inc/win/saltimer.h
@@ -47,6 +47,7 @@ public:
     virtual void Stop() override;
 
     inline bool IsDirectTimeout() const;
+    inline bool HasTimerElapsed() const;
 };
 
 inline bool WinSalTimer::IsDirectTimeout() const
@@ -54,6 +55,11 @@ inline bool WinSalTimer::IsDirectTimeout() const
     return m_bDirectTimeout;
 }
 
+inline bool WinSalTimer::HasTimerElapsed() const
+{
+    return m_bDirectTimeout || ExistsValidEvent();
+}
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 38db3d3bb17c..ade332297fc6 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -689,10 +689,119 @@ LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPa
     return nRet;
 }
 
+struct MsgRange
+{
+    UINT nStart;
+    UINT nEnd;
+};
+
+static std::vector<MsgRange> GetOtherRanges( VclInputFlags nType )
+{
+    assert( nType != VCL_INPUT_ANY );
+
+    // this array must be kept sorted!
+    const UINT nExcludeMsgIds[] =
+    {
+        0,
+
+        WM_MOVE, // 3
+        WM_SIZE, // 5
+        WM_PAINT, // 15
+        WM_KEYDOWN, // 256
+        WM_TIMER, // 275
+
+        WM_MOUSEFIRST, // 512
+        513,
+        514,
+        515,
+        516,
+        517,
+        518,
+        519,
+        520,
+        WM_MOUSELAST, // 521
+
+        SAL_MSG_POSTMOVE, // WM_USER+136
+        SAL_MSG_POSTCALLSIZE, // WM_USER+137
+
+        SAL_MSG_TIMER_CALLBACK, // WM_USER+162
+
+        UINT_MAX
+    };
+    const unsigned MAX_EXCL = SAL_N_ELEMENTS( nExcludeMsgIds );
+
+    bool aExcludeMsgList[ MAX_EXCL ] = { false, };
+    std::vector<MsgRange> aResult;
+
+    // set the excluded values
+    if ( !(nType & VclInputFlags::MOUSE) )
+    {
+        for ( unsigned i = 0; nExcludeMsgIds[ 6 + i ] <= WM_MOUSELAST; ++i )
+            aExcludeMsgList[ 6 + i ] = true;
+    }
+
+    if ( !(nType & VclInputFlags::KEYBOARD) )
+        aExcludeMsgList[ 4 ] = true;
+
+    if ( !(nType & VclInputFlags::PAINT) )
+    {
+        aExcludeMsgList[ 1 ] = true;
+        aExcludeMsgList[ 2 ] = true;
+        aExcludeMsgList[ 3 ] = true;
+        aExcludeMsgList[ 16 ] = true;
+        aExcludeMsgList[ 17 ] = true;
+    }
+
+    if ( !(nType & VclInputFlags::TIMER) )
+    {
+        aExcludeMsgList[ 5 ]  = true;
+        aExcludeMsgList[ 18 ]  = true;
+    }
+
+    // build the message ranges to check
+    MsgRange aRange = { 0, 0 };
+    bool doEnd = true;
+    for ( unsigned i = 1; i < MAX_EXCL; ++i )
+    {
+        if ( aExcludeMsgList[ i ] )
+        {
+            if ( !doEnd )
+            {
+                if ( nExcludeMsgIds[ i ] == aRange.nStart )
+                    ++aRange.nStart;
+                else
+                    doEnd = true;
+            }
+            if ( doEnd )
+            {
+                aRange.nEnd = nExcludeMsgIds[ i ] - 1;
+                aResult.push_back( aRange );
+                doEnd = false;
+                aRange.nStart = aRange.nEnd + 2;
+            }
+        }
+    }
+
+    if ( aRange.nStart != UINT_MAX )
+    {
+        aRange.nEnd = UINT_MAX;
+        aResult.push_back( aRange );
+    }
+
+    return aResult;
+}
+
 bool WinSalInstance::AnyInput( VclInputFlags nType )
 {
     MSG aMsg;
 
+    if ( nType & VclInputFlags::TIMER )
+    {
+        const WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
+        if ( pTimer && pTimer->HasTimerElapsed() )
+            return true;
+    }
+
     if ( (nType & VCL_INPUT_ANY) == VCL_INPUT_ANY )
     {
         // revert bugfix for #108919# which never reported timeouts when called from the timer handler
@@ -702,32 +811,52 @@ bool WinSalInstance::AnyInput( VclInputFlags nType )
     }
     else
     {
-        if ( nType & VclInputFlags::MOUSE )
-        {
-            // Test for mouse input
-            if ( PeekMessageW( &aMsg, nullptr, WM_MOUSEFIRST, WM_MOUSELAST,
-                                  PM_NOREMOVE | PM_NOYIELD ) )
-                return true;
-        }
+        const bool bCheck_KEYBOARD (nType & VclInputFlags::KEYBOARD);
+        const bool bCheck_OTHER    (nType & VclInputFlags::OTHER);
 
-        if ( nType & VclInputFlags::KEYBOARD )
+        // If there is a modifier key event, it counts as OTHER
+        // Previously we were simply ignoring these events...
+        if ( bCheck_KEYBOARD || bCheck_OTHER )
         {
-            // Test for key input
             if ( PeekMessageW( &aMsg, nullptr, WM_KEYDOWN, WM_KEYDOWN,
                                   PM_NOREMOVE | PM_NOYIELD ) )
             {
-                if ( (aMsg.wParam == VK_SHIFT)   ||
-                     (aMsg.wParam == VK_CONTROL) ||
-                     (aMsg.wParam == VK_MENU) )
-                    return false;
-                else
+                const bool bIsModifier = ( (aMsg.wParam == VK_SHIFT) ||
+                    (aMsg.wParam == VK_CONTROL) || (aMsg.wParam == VK_MENU) );
+                if ( bCheck_KEYBOARD && !bIsModifier )
+                    return true;
+                if ( bCheck_OTHER && bIsModifier )
                     return true;
             }
         }
 
+        // Other checks for all messages not excluded.
+        // The less we exclude, the less ranges have to be checked!
+        if ( bCheck_OTHER )
+        {
+            // TIMER and KEYBOARD are already handled, so always exclude them!
+            VclInputFlags nOtherType = nType &
+                ~VclInputFlags(VclInputFlags::KEYBOARD | VclInputFlags::TIMER);
+
+            std::vector<MsgRange> aMsgRangeList( GetOtherRanges( nOtherType ) );
+            for ( MsgRange aRange : aMsgRangeList )
+                if ( PeekMessageW( &aMsg, nullptr, aRange.nStart,
+                                   aRange.nEnd, PM_NOREMOVE | PM_NOYIELD ) )
+                    return true;
+
+            // MOUSE and PAINT already handled, so skip futher checks
+            return false;
+        }
+
+        if ( nType & VclInputFlags::MOUSE )
+        {
+            if ( PeekMessageW( &aMsg, nullptr, WM_MOUSEFIRST, WM_MOUSELAST,
+                                  PM_NOREMOVE | PM_NOYIELD ) )
+                return true;
+        }
+
         if ( nType & VclInputFlags::PAINT )
         {
-            // Test for paint input
             if ( PeekMessageW( &aMsg, nullptr, WM_PAINT, WM_PAINT,
                                   PM_NOREMOVE | PM_NOYIELD ) )
                 return true;
@@ -748,22 +877,6 @@ bool WinSalInstance::AnyInput( VclInputFlags nType )
                                   PM_NOREMOVE | PM_NOYIELD ) )
                 return true;
         }
-
-        if ( nType & VclInputFlags::TIMER )
-        {
-            // Test for timer input
-            if ( PeekMessageW( &aMsg, nullptr, WM_TIMER, WM_TIMER,
-                                  PM_NOREMOVE | PM_NOYIELD ) )
-                return true;
-
-        }
-
-        if ( nType & VclInputFlags::OTHER )
-        {
-            // Test for any input
-            if ( PeekMessageW( &aMsg, nullptr, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
-                return true;
-        }
     }
 
     return false;


More information about the Libreoffice-commits mailing list