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. Also, only native events and timers need to be dispatched to redraw the window so skip dispatching user events when a window is in live resize. Lastly, only higher priority tasks need to be fired to redraw the window so skip firing potentially long-running tasks, such as the Writer idle layout timer, when a window is in live resize. Change-Id: I5d449caa432399e836b8e59781e5cc53af718873 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145211 Tested-by: Jenkins Reviewed-by: Patrick Luby <plubius@neooffice.org>
This commit is contained in:
@@ -29,8 +29,12 @@ enum class SalEvent;
|
||||
AquaSalFrame* mpFrame;
|
||||
id mDraggingDestinationHandler;
|
||||
BOOL mbInLiveResize;
|
||||
BOOL mbInWindowDidResize;
|
||||
NSTimer* mpLiveResizeTimer;
|
||||
}
|
||||
-(id)initWithSalFrame: (AquaSalFrame*)pFrame;
|
||||
-(void)clearLiveResizeTimer;
|
||||
-(void)dealloc;
|
||||
-(BOOL)canBecomeKeyWindow;
|
||||
-(void)displayIfNeeded;
|
||||
-(void)windowDidBecomeKey: (NSNotification*)pNotification;
|
||||
@@ -63,6 +67,8 @@ enum class SalEvent;
|
||||
|
||||
-(void)endExtTextInput;
|
||||
-(void)endExtTextInput:(EndExtTextInputFlags)nFlags;
|
||||
|
||||
-(void)windowDidResizeWithTimer:(NSTimer *)pTimer;
|
||||
@end
|
||||
|
||||
@interface SalFrameView : AquaA11yWrapper <NSTextInputClient>
|
||||
|
||||
@@ -89,7 +89,6 @@ public:
|
||||
int mnActivePrintJobs;
|
||||
osl::Mutex maUserEventListMutex;
|
||||
osl::Condition maWaitingYieldCond;
|
||||
bool mbIsLiveResize;
|
||||
bool mbNoYieldLock;
|
||||
bool mbTimerProcessed;
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ struct ImplSVWinData
|
||||
StartAutoScrollFlags mnAutoScrollFlags = StartAutoScrollFlags::NONE; // auto scroll flags
|
||||
bool mbNoDeactivate = false; // true: do not execute Deactivate
|
||||
bool mbNoSaveFocus = false; // true: menus must not save/restore focus
|
||||
bool mbIsLiveResize = false; // true: skip waiting for events and low priority timers
|
||||
};
|
||||
|
||||
typedef std::vector< std::pair< OUString, FieldUnit > > FieldUnitStringList;
|
||||
|
||||
+64
-13
@@ -170,6 +170,8 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
{
|
||||
mDraggingDestinationHandler = nil;
|
||||
mbInLiveResize = NO;
|
||||
mbInWindowDidResize = NO;
|
||||
mpLiveResizeTimer = nil;
|
||||
mpFrame = pFrame;
|
||||
NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.x()), static_cast<CGFloat>(pFrame->maGeometry.y()) },
|
||||
{ static_cast<CGFloat>(pFrame->maGeometry.width()), static_cast<CGFloat>(pFrame->maGeometry.height()) } };
|
||||
@@ -210,6 +212,22 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
return static_cast<SalFrameWindow *>(pNSWindow);
|
||||
}
|
||||
|
||||
-(void)clearLiveResizeTimer
|
||||
{
|
||||
if ( mpLiveResizeTimer )
|
||||
{
|
||||
[mpLiveResizeTimer invalidate];
|
||||
[mpLiveResizeTimer release];
|
||||
mpLiveResizeTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
[self clearLiveResizeTimer];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(AquaSalFrame*)getSalFrame
|
||||
{
|
||||
return mpFrame;
|
||||
@@ -318,12 +336,29 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
(void)pNotification;
|
||||
SolarMutexGuard aGuard;
|
||||
|
||||
if ( mbInWindowDidResize )
|
||||
return;
|
||||
|
||||
mbInWindowDidResize = YES;
|
||||
|
||||
if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
|
||||
{
|
||||
mpFrame->UpdateFrameGeometry();
|
||||
mpFrame->CallCallback( SalEvent::Resize, nullptr );
|
||||
|
||||
bool bInLiveResize = [self inLiveResize];
|
||||
ImplSVData* pSVData = ImplGetSVData();
|
||||
assert( pSVData );
|
||||
if ( pSVData )
|
||||
{
|
||||
const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize;
|
||||
if ( bWasLiveResize != bInLiveResize )
|
||||
{
|
||||
pSVData->mpWinData->mbIsLiveResize = bInLiveResize;
|
||||
Scheduler::Wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
if ( bInLiveResize || mbInLiveResize )
|
||||
{
|
||||
mbInLiveResize = bInLiveResize;
|
||||
@@ -370,21 +405,31 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
{
|
||||
// tdf#152703 Force repaint after live resizing ends
|
||||
// Repost this notification so that this selector will be called
|
||||
// at least once after live resizing ends. Pass nil for
|
||||
// withObject: since it is unused and makes it easier to cancel
|
||||
// all pending selector execution when live resizing ends.
|
||||
[self performSelector:@selector(windowDidResize:) withObject:nil afterDelay:0.1f];
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(windowDidResize:) object:nil];
|
||||
// at least once after live resizing ends
|
||||
if ( !mpLiveResizeTimer )
|
||||
{
|
||||
mpLiveResizeTimer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(windowDidResizeWithTimer:) userInfo:pNotification repeats:YES];
|
||||
if ( mpLiveResizeTimer )
|
||||
{
|
||||
[mpLiveResizeTimer retain];
|
||||
|
||||
// The timer won't fire without a call to
|
||||
// Application::Reschedule() unless we copy the fix for
|
||||
// #i84055# from vcl/osx/saltimer.cxx and add the timer
|
||||
// to the NSEventTrackingRunLoopMode run loop mode
|
||||
[[NSRunLoop currentRunLoop] addTimer:mpLiveResizeTimer forMode:NSEventTrackingRunLoopMode];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self clearLiveResizeTimer];
|
||||
mpFrame->SendPaintEvent();
|
||||
}
|
||||
}
|
||||
|
||||
mbInWindowDidResize = NO;
|
||||
}
|
||||
|
||||
-(void)windowDidMiniaturize: (NSNotification*)pNotification
|
||||
@@ -523,6 +568,12 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
[pView endExtTextInput:nFlags];
|
||||
}
|
||||
|
||||
-(void)windowDidResizeWithTimer:(NSTimer *)pTimer
|
||||
{
|
||||
if ( pTimer )
|
||||
[self windowDidResize:[pTimer userInfo]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SalFrameView
|
||||
@@ -602,9 +653,9 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
|
||||
-(void)drawRect: (NSRect)aRect
|
||||
{
|
||||
AquaSalInstance *pInstance = GetSalData()->mpInstance;
|
||||
assert(pInstance);
|
||||
if (!pInstance)
|
||||
ImplSVData* pSVData = ImplGetSVData();
|
||||
assert( pSVData );
|
||||
if ( !pSVData )
|
||||
return;
|
||||
|
||||
SolarMutexGuard aGuard;
|
||||
@@ -612,10 +663,10 @@ static AquaSalFrame* getMouseContainerFrame()
|
||||
return;
|
||||
|
||||
const bool bIsLiveResize = [self inLiveResize];
|
||||
const bool bWasLiveResize = pInstance->mbIsLiveResize;
|
||||
const bool bWasLiveResize = pSVData->mpWinData->mbIsLiveResize;
|
||||
if (bWasLiveResize != bIsLiveResize)
|
||||
{
|
||||
pInstance->mbIsLiveResize = bIsLiveResize;
|
||||
pSVData->mpWinData->mbIsLiveResize = bIsLiveResize;
|
||||
Scheduler::Wakeup();
|
||||
}
|
||||
|
||||
|
||||
+12
-2
@@ -368,7 +368,6 @@ VCLPLUG_OSX_PUBLIC SalInstance* create_SalInstance()
|
||||
AquaSalInstance::AquaSalInstance()
|
||||
: SalInstance(std::make_unique<SalYieldMutex>())
|
||||
, mnActivePrintJobs( 0 )
|
||||
, mbIsLiveResize( false )
|
||||
, mbNoYieldLock( false )
|
||||
, mbTimerProcessed( false )
|
||||
{
|
||||
@@ -556,6 +555,13 @@ 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();
|
||||
@@ -565,7 +571,11 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
|
||||
ReleasePoolHolder aReleasePool;
|
||||
|
||||
// first, process current user events
|
||||
bool bHadEvent = DispatchUserEvents( bHandleAllCurrentEvents );
|
||||
// Related: tdf#152703 Eliminate potential blocking during live resize
|
||||
// Only native events and timers need to be dispatched to redraw
|
||||
// the window so skip dispatching user events when a window is in
|
||||
// live resize
|
||||
bool bHadEvent = ( !ImplGetSVData()->mpWinData->mbIsLiveResize && DispatchUserEvents( bHandleAllCurrentEvents ) );
|
||||
if ( !bHandleAllCurrentEvents && bHadEvent )
|
||||
return true;
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ void AquaSalTimer::Start( sal_uInt64 nMS )
|
||||
return;
|
||||
}
|
||||
|
||||
m_bDirectTimeout = (0 == nMS) && !pSalData->mpInstance->mbIsLiveResize;
|
||||
m_bDirectTimeout = (0 == nMS) && !ImplGetSVData()->mpWinData->mbIsLiveResize;
|
||||
if ( m_bDirectTimeout )
|
||||
Stop();
|
||||
else
|
||||
@@ -142,7 +142,7 @@ void AquaSalTimer::callTimerCallback()
|
||||
|
||||
void AquaSalTimer::handleTimerElapsed()
|
||||
{
|
||||
if ( m_bDirectTimeout || GetSalData()->mpInstance->mbIsLiveResize )
|
||||
if ( m_bDirectTimeout || ImplGetSVData()->mpWinData->mbIsLiveResize )
|
||||
{
|
||||
// Stop the timer, as it is just invalidated after the firing function
|
||||
Stop();
|
||||
|
||||
@@ -359,6 +359,13 @@ void Scheduler::CallbackTaskScheduling()
|
||||
|
||||
for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
|
||||
{
|
||||
// Related: tdf#152703 Eliminate potential blocking during live resize
|
||||
// Only higher priority tasks need to be fired to redraw the window
|
||||
// so skip firing potentially long-running tasks, such as the Writer
|
||||
// idle layout timer, when a window is in live resize
|
||||
if ( ImplGetSVData()->mpWinData->mbIsLiveResize && nTaskPriority == static_cast<int>(TaskPriority::LOWEST) )
|
||||
continue;
|
||||
|
||||
pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
|
||||
pPrevSchedulerData = nullptr;
|
||||
while (pSchedulerData)
|
||||
|
||||
Reference in New Issue
Block a user