From afba8a7ad491208cc76791f491ea2b6ccd636858 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 12:52:57 +0200 Subject: [PATCH] AutomationEditor: thread-safe handling of AutomationPattern pointer It was not possible to call any of the functions of AutomationEditor from threads other than the main GUI thread as the m_pattern pointer was not protected by a mutex. It is however desired to be able to call for example AutomationEditor::setCurrentPattern(...) from different threads (mainly required when deleting AutomationPatterns in other threads). Thus made this method and all accesses to the m_pattern pointer thread-safe. --- include/automation_editor.h | 5 +- src/gui/automation_editor.cpp | 119 +++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 46 deletions(-) diff --git a/include/automation_editor.h b/include/automation_editor.h index f5f73cb0a..ecce76967 100644 --- a/include/automation_editor.h +++ b/include/automation_editor.h @@ -24,10 +24,10 @@ * */ - #ifndef _AUTOMATION_EDITOR_H #define _AUTOMATION_EDITOR_H +#include #include #include "lmms_basics.h" @@ -76,6 +76,7 @@ public: public slots: void update(); + void updateAfterPatternChange(); protected: @@ -190,6 +191,7 @@ private: ComboBoxModel m_zoomingYModel; ComboBoxModel m_quantizeModel; + QMutex m_patternMutex; automationPattern * m_pattern; float m_minLevel; float m_maxLevel; @@ -242,6 +244,7 @@ private: signals: + void currentPatternChanged(); void positionChanged( const midiTime & ); } ; diff --git a/src/gui/automation_editor.cpp b/src/gui/automation_editor.cpp index 95eb31324..9ac296da1 100644 --- a/src/gui/automation_editor.cpp +++ b/src/gui/automation_editor.cpp @@ -24,10 +24,8 @@ * */ - #include "automation_editor.h" - #include #include #include @@ -77,6 +75,7 @@ automationEditor::automationEditor() : m_zoomingXModel(), m_zoomingYModel(), m_quantizeModel(), + m_patternMutex( QMutex::Recursive ), m_pattern( NULL ), m_minLevel( 0 ), m_maxLevel( 0 ), @@ -94,6 +93,10 @@ automationEditor::automationEditor() : m_editMode( ModeDraw ), m_scrollBack( false ) { + connect( this, SIGNAL( currentPatternChanged() ), + this, SLOT( updateAfterPatternChange() ), + Qt::QueuedConnection ); + // init pixmaps if( s_toolDraw == NULL ) { @@ -373,6 +376,8 @@ automationEditor::automationEditor() : automationEditor::~automationEditor() { + m_zoomingXModel.disconnect(); + m_zoomingYModel.disconnect(); } @@ -380,10 +385,39 @@ automationEditor::~automationEditor() void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) { + m_patternMutex.lock(); m_pattern = _new_pattern; + m_patternMutex.unlock(); + + emit currentPatternChanged(); +} + + + + +void automationEditor::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + MainWindow::saveWidgetState( this, _this ); +} + + + + +void automationEditor::loadSettings( const QDomElement & _this ) +{ + MainWindow::restoreWidgetState( this, _this ); +} + + + + +void automationEditor::updateAfterPatternChange() +{ + QMutexLocker m( &m_patternMutex ); + m_currentPosition = 0; - if( validPattern() == false ) + if( !validPattern() ) { setWindowTitle( tr( "Automation Editor - no pattern" ) ); m_minLevel = m_maxLevel = m_scrollLevel = 0; @@ -401,8 +435,7 @@ void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) // of levels and so on...) resizeEvent( NULL ); - setWindowTitle( tr( "Automation Editor - %1" ).arg( - m_pattern->name() ) ); + setWindowTitle( tr( "Automation Editor - %1" ).arg( m_pattern->name() ) ); update(); } @@ -410,17 +443,16 @@ void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) -void automationEditor::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void automationEditor::update() { - MainWindow::saveWidgetState( this, _this ); -} + QWidget::update(); - - - -void automationEditor::loadSettings( const QDomElement & _this ) -{ - MainWindow::restoreWidgetState( this, _this ); + QMutexLocker m( &m_patternMutex ); + // Note detuning? + if( m_pattern && !m_pattern->getTrack() ) + { + engine::getPianoRoll()->update(); + } } @@ -684,7 +716,8 @@ void automationEditor::drawLine( int _x0, float _y0, int _x1, float _y1 ) void automationEditor::mousePressEvent( QMouseEvent * _me ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -847,7 +880,8 @@ void automationEditor::mouseReleaseEvent( QMouseEvent * _me ) void automationEditor::mouseMoveEvent( QMouseEvent * _me ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { update(); return; @@ -1221,6 +1255,8 @@ inline void automationEditor::drawCross( QPainter & _p ) void automationEditor::paintEvent( QPaintEvent * _pe ) { + QMutexLocker m( &m_patternMutex ); + QStyleOption opt; opt.initFrom( this ); QPainter p( this ); @@ -1242,7 +1278,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) Qt::Alignment text_flags = (Qt::Alignment)( Qt::AlignRight | Qt::AlignVCenter ); - if( m_pattern ) + if( validPattern() ) { if( m_y_auto ) { @@ -1391,7 +1427,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) qSwap( selLevel_start, selLevel_end ); } - if( validPattern() == true ) + if( validPattern() ) { timeMap & time_map = m_pattern->getTimeMap(); timeMap::iterator it = time_map.begin(); @@ -1528,7 +1564,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) p.drawRect( x + ValuesWidth, y, w, h ); // TODO: Get this out of paint event - int l = ( validPattern() == true )? (int) m_pattern->length() : 0; + int l = validPattern() ? (int) m_pattern->length() : 0; // reset scroll-range if( m_leftRightScroll->maximum() != l ) @@ -1537,7 +1573,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) m_leftRightScroll->setPageStep( l ); } - if( validPattern() == true ) + if( validPattern() ) { drawCross( p ); } @@ -1666,7 +1702,9 @@ float automationEditor::getLevel( int _y ) inline bool automationEditor::inBBEditor() { - return( m_pattern->getTrack()->getTrackContainer() + QMutexLocker m( &m_patternMutex ); + return( validPattern() && + m_pattern->getTrack()->getTrackContainer() == engine::getBBTrackContainer() ); } @@ -1675,7 +1713,9 @@ inline bool automationEditor::inBBEditor() void automationEditor::play() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + + if( !validPattern() ) { return; } @@ -1749,6 +1789,8 @@ void automationEditor::play() void automationEditor::stop() { + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; @@ -1832,7 +1874,8 @@ void automationEditor::moveButtonToggled() void automationEditor::selectAll() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1870,7 +1913,8 @@ void automationEditor::selectAll() // returns vector with pointers to all selected values void automationEditor::getSelectedValues( timeMap & _selected_values ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1938,7 +1982,8 @@ void automationEditor::copySelectedValues() void automationEditor::cutSelectedValues() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1969,12 +2014,8 @@ void automationEditor::cutSelectedValues() void automationEditor::pasteValues() { - if( validPattern() == false ) - { - return; - } - - if( !m_valuesToCopy.isEmpty() ) + QMutexLocker m( &m_patternMutex ); + if( validPattern() && !m_valuesToCopy.isEmpty() ) { for( timeMap::iterator it = m_valuesToCopy.begin(); it != m_valuesToCopy.end(); ++it ) @@ -1996,7 +2037,8 @@ void automationEditor::pasteValues() void automationEditor::deleteSelectedValues() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -2140,19 +2182,6 @@ void automationEditor::updateTopBottomLevels() -void automationEditor::update() -{ - QWidget::update(); - // Note detuning? - if( m_pattern && !m_pattern->getTrack() ) - { - engine::getPianoRoll()->update(); - } -} - - - - #include "moc_automation_editor.cxx"