tdf#155092 don't dispatch left mouse up events during live resizing

If this is a left mouse up event, dispatching this event
will trigger tdf#155092 to occur in the next mouse down
event. So do not dispatch this event and push it back onto
the front of the event queue so no more events will be
dispatched until live resizing ends. Surprisingly, live
resizing appears to end in the next mouse down event.

Also, include commit 54da842381ccb554d3cadc876f23cf183d21bf1a
which, while it failed to fix tdf#155092, the switch to using
the newer tracking areas selectors instead of the older
tracking rectangles selectors still gives more control
over mouse entered, mouse exited, and mouse moved events.

Lastly, include commit 3b942f6efa8ffd11374031e4af8dbcb48a8962d1
which fixes some vertical shifing of the window's content
while live resizing with Skia disabled.

Change-Id: Ie93ed496e1f0e2a1711284ab205c6b245f71647c
Reviewed-by: Patrick Luby <plubius@libreoffice.org>
(cherry picked from commit 8a5da079592377cf69735973d922fc19e8ac763d)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160029
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h
index 950c8d6..806b751 100644
--- a/vcl/inc/osx/salframe.h
+++ b/vcl/inc/osx/salframe.h
@@ -78,7 +78,6 @@ public:

    PointerStyle                    mePointerStyle;         // currently active pointer style

    NSTrackingRectTag               mnTrackingRectTag;      // used to get enter/leave messages
    NSRect                          maTrackingRect;

    CGMutablePathRef                mrClippingPath;         // used for "shaping"
diff --git a/vcl/inc/osx/salframeview.h b/vcl/inc/osx/salframeview.h
index f9eca27..2b1a3f9 100644
--- a/vcl/inc/osx/salframeview.h
+++ b/vcl/inc/osx/salframeview.h
@@ -28,7 +28,6 @@ enum class SalEvent;
{
    AquaSalFrame*       mpFrame;
    id mDraggingDestinationHandler;
    BOOL                mbInLiveResize;
    BOOL                mbInWindowDidResize;
    NSTimer*            mpLiveResizeTimer;
}
@@ -46,6 +45,8 @@ enum class SalEvent;
-(void)windowDidDeminiaturize: (NSNotification*)pNotification;
-(BOOL)windowShouldClose: (NSNotification*)pNotification;
-(void)windowDidChangeBackingProperties:(NSNotification *)pNotification;
-(void)windowWillStartLiveResize:(NSNotification *)pNotification;
-(void)windowDidEndLiveResize:(NSNotification *)pNotification;
//-(void)willEncodeRestorableState:(NSCoder*)pCoderState;
//-(void)didDecodeRestorableState:(NSCoder*)pCoderState;
//-(void)windowWillEnterVersionBrowser:(NSNotification*)pNotification;
diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx
index 028e10c..1d7f0af 100644
--- a/vcl/osx/salframe.cxx
+++ b/vcl/osx/salframe.cxx
@@ -84,7 +84,6 @@ AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle 
    mpMenu( nullptr ),
    mnExtStyle( 0 ),
    mePointerStyle( PointerStyle::Arrow ),
    mnTrackingRectTag( 0 ),
    mrClippingPath( nullptr ),
    mnICOptions( InputContextFlags::NONE ),
    mnBlinkCursorDelay( nMinBlinkCursorDelay ),
@@ -237,14 +236,27 @@ void AquaSalFrame::initWindowAndView()
    if( mnStyle & SalFrameStyleFlags::TOOLTIP )
        [mpNSWindow setIgnoresMouseEvents: YES];
    else
        [mpNSWindow setAcceptsMouseMovedEvents: YES];
        // Related: tdf#155092 mouse events are now handled by tracking areas
        [mpNSWindow setAcceptsMouseMovedEvents: NO];
    [mpNSWindow setHasShadow: YES];

    [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];

    [mpNSWindow setRestorable:NO];
    const NSRect aRect = { NSZeroPoint, NSMakeSize(maGeometry.width(), maGeometry.height()) };
    mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];

    // tdf#155092 use tracking areas instead of tracking rectangles
    // Apparently, the older, tracking rectangles selectors cause
    // unexpected window resizing upon the first mouse down after the
    // window has been manually resized so switch to the newer,
    // tracking areas selectors. Also, the NSTrackingInVisibleRect
    // option allows us to create one single tracking area that
    // resizes itself automatically over the lifetime of the view.
    // Note: for some unknown reason, both NSTrackingMouseMoved and
    // NSTrackingAssumeInside are necessary options for this fix
    // to work.
    NSTrackingArea *pTrackingArea = [[NSTrackingArea alloc] initWithRect: [mpNSView bounds] options: ( NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingAssumeInside | NSTrackingInVisibleRect ) owner: mpNSView userInfo: nil];
    [mpNSView addTrackingArea: pTrackingArea];
    [pTrackingArea release];

    maSysData.mpNSView = mpNSView;

@@ -1831,7 +1843,6 @@ void AquaSalFrame::SetParent( SalFrame* pNewParent )

void AquaSalFrame::UpdateFrameGeometry()
{
    bool bFirstTime = (mnTrackingRectTag == 0);
    mbGeometryDidChange = false;

    if ( !mpNSWindow )
@@ -1847,7 +1858,7 @@ void AquaSalFrame::UpdateFrameGeometry()
    if( pScreen )
    {
        NSRect aNewScreenRect = [pScreen frame];
        if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
        if (!NSEqualRects(maScreenRect, aNewScreenRect))
        {
            mbGeometryDidChange = true;
            maScreenRect = aNewScreenRect;
@@ -1856,7 +1867,7 @@ void AquaSalFrame::UpdateFrameGeometry()
        if( pScreens )
        {
            unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
            if (bFirstTime || maGeometry.screen() != nNewDisplayScreenNumber)
            if (maGeometry.screen() != nNewDisplayScreenNumber)
            {
                mbGeometryDidChange = true;
                maGeometry.setScreen(nNewDisplayScreenNumber);
@@ -1869,22 +1880,17 @@ void AquaSalFrame::UpdateFrameGeometry()

    NSRect aTrackRect = { NSZeroPoint, aContentRect.size };

    if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
    if (!NSEqualRects(maTrackingRect, aTrackRect))
    {
        mbGeometryDidChange = true;
        maTrackingRect = aTrackRect;

        // release old track rect
        [mpNSView removeTrackingRect: mnTrackingRectTag];
        // install the new track rect
        mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
    }

    // convert to vcl convention
    CocoaToVCL( aFrameRect );
    CocoaToVCL( aContentRect );

    if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
    if (!NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
    {
        mbGeometryDidChange = true;

diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm
index 68681ba..5cf9fb9 100644
--- a/vcl/osx/salframeview.mm
+++ b/vcl/osx/salframeview.mm
@@ -194,6 +194,21 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
    return pRet;
}

// Update ImplGetSVData()->mpWinData->mbIsLiveResize
static void updateWinDataInLiveResize(bool bInLiveResize)
{
    ImplSVData* pSVData = ImplGetSVData();
    assert( pSVData );
    if ( pSVData )
    {
        if ( pSVData->mpWinData->mbIsLiveResize != bInLiveResize )
        {
            pSVData->mpWinData->mbIsLiveResize = bInLiveResize;
            Scheduler::Wakeup();
        }
    }
}

@interface NSResponder (SalFrameWindow)
-(BOOL)accessibilityIsIgnored;
@end
@@ -202,7 +217,6 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
-(id)initWithSalFrame: (AquaSalFrame*)pFrame
{
    mDraggingDestinationHandler = nil;
    mbInLiveResize = NO;
    mbInWindowDidResize = NO;
    mpLiveResizeTimer = nil;
    mpFrame = pFrame;
@@ -384,23 +398,9 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
        mpFrame->UpdateFrameGeometry();
        mpFrame->CallCallback( SalEvent::Resize, nullptr );

        bool bInLiveResize = [self inLiveResize];
        ImplSVData* pSVData = ImplGetSVData();
        assert( pSVData );
        if ( pSVData )
        updateWinDataInLiveResize( [self inLiveResize] );
        if ( ImplGetSVData()->mpWinData->mbIsLiveResize )
        {
            const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize;
            if ( bWasLiveResize != bInLiveResize )
            {
                pSVData->mpWinData->mbIsLiveResize = bInLiveResize;
                Scheduler::Wakeup();
            }
        }

        if ( bInLiveResize || mbInLiveResize )
        {
            mbInLiveResize = bInLiveResize;

#if HAVE_FEATURE_SKIA
            // Related: tdf#152703 Eliminate empty window with Skia/Metal while resizing
            // The window will clear its background so when Skia/Metal is
@@ -439,7 +439,7 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
            [self setMinSize:aMinSize];
            [self setMaxSize:aMaxSize];

            if ( mbInLiveResize )
            if ( ImplGetSVData()->mpWinData->mbIsLiveResize )
            {
                // tdf#152703 Force repaint after live resizing ends
                // Repost this notification so that this selector will be called
@@ -560,6 +560,20 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
#endif
}

-(void)windowWillStartLiveResize:(NSNotification *)pNotification
{
    SolarMutexGuard aGuard;

    updateWinDataInLiveResize(true);
}

-(void)windowDidEndLiveResize:(NSNotification *)pNotification
{
    SolarMutexGuard aGuard;

    updateWinDataInLiveResize(false);
}

-(void)dockMenuItemTriggered: (id)sender
{
    (void)sender;
@@ -761,13 +775,7 @@ static NSArray *getMergedAccessibilityChildren(NSArray *pDefaultChildren, NSArra
    if (!mpFrame || !AquaSalFrame::isAlive(mpFrame))
        return;

    const bool bIsLiveResize = [self inLiveResize];
    const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize;
    if (bWasLiveResize != bIsLiveResize)
    {
        pSVData->mpWinData->mbIsLiveResize = bIsLiveResize;
        Scheduler::Wakeup();
    }
    updateWinDataInLiveResize([self inLiveResize]);

    AquaSalGraphics* pGraphics = mpFrame->mpGraphics;
    if (pGraphics)
diff --git a/vcl/osx/salgdiutils.cxx b/vcl/osx/salgdiutils.cxx
index 7e4bd23..a944529 100644
--- a/vcl/osx/salgdiutils.cxx
+++ b/vcl/osx/salgdiutils.cxx
@@ -311,6 +311,22 @@ void AquaSalGraphics::UpdateWindow( NSRect& )

        rCGContextHolder.saveState();

        // Related: tdf#155092 translate Y coordinate for height differences
        // When in live resize, the NSView's height may have changed before
        // the CGLayer has been resized. This causes the CGLayer's content
        // to be drawn just above or below the top left corner of the view
        // so translate the Y coordinate by any difference between the
        // NSView's height and the CGLayer's height.
        NSView *pView = maShared.mpFrame->mpNSView;
        if (pView)
        {
            // Use the NSView's bounds, not its frame, to properly handle
            // any rotation and/or scaling that might have been already
            // applied to the view
            CGFloat fTranslateY = [pView bounds].size.height - maShared.maLayer.getSizePoints().height;
            CGContextTranslateCTM(rCGContextHolder.get(), 0, fTranslateY);
        }

        CGMutablePathRef rClip = maShared.mpFrame->getClipPath();
        if (rClip)
        {
diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx
index be33e8a..d7b85b1 100644
--- a/vcl/osx/salinst.cxx
+++ b/vcl/osx/salinst.cxx
@@ -555,13 +555,6 @@ static bool isWakeupEvent( NSEvent *pEvent )

bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
{
    // Related: tdf#152703 Eliminate potential blocking during live resize
    // Some events and timers call Application::Reschedule() or
    // Application::Yield() so don't block and wait for events when a
    // window is in live resize
    if ( ImplGetSVData()->mpWinData->mbIsLiveResize )
        bWait = false;

    // ensure that the per thread autorelease pool is top level and
    // will therefore not be destroyed by cocoa implicitly
    SalData::ensureThreadAutoreleasePool();
@@ -598,6 +591,19 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
                            dequeue: YES];
            if( pEvent )
            {
                // tdf#155092 don't dispatch left mouse up events during live resizing
                // If this is a left mouse up event, dispatching this event
                // will trigger tdf#155092 to occur in the next mouse down
                // event. So do not dispatch this event and push it back onto
                // the front of the event queue so no more events will be
                // dispatched until live resizing ends. Surprisingly, live
                // resizing appears to end in the next mouse down event.
                if ( ImplGetSVData()->mpWinData->mbIsLiveResize && [pEvent type] == NSEventTypeLeftMouseUp )
                {
                    [NSApp postEvent: pEvent atStart: YES];
                    return false;
                }

                [NSApp sendEvent: pEvent];
                if ( isWakeupEvent( pEvent ) )
                    continue;
@@ -619,7 +625,11 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
        }

        // if we had no event yet, wait for one if requested
        if( bWait && ! bHadEvent )
        // Related: tdf#152703 Eliminate potential blocking during live resize
        // Some events and timers call Application::Reschedule() or
        // Application::Yield() so don't block and wait for events when a
        // window is in live resize
        if( bWait && ! bHadEvent && !ImplGetSVData()->mpWinData->mbIsLiveResize )
        {
            SolarMutexReleaser aReleaser;