Qt: remove mutex, defer loading of grid items into layout, use guarded pointers for exec() operations, misc cleanup

This commit is contained in:
Brad Parker 2018-05-06 20:50:54 -04:00
parent de71a4dee7
commit 2a784ae1bc
5 changed files with 56 additions and 37 deletions

View File

@ -336,7 +336,8 @@ OBJ += ui/drivers/ui_qt.o \
ui/drivers/qt/flowlayout.o ui/drivers/qt/flowlayout.o
MOC_HEADERS += ui/drivers/ui_qt.h \ MOC_HEADERS += ui/drivers/ui_qt.h \
ui/drivers/qt/ui_qt_load_core_window.h ui/drivers/qt/ui_qt_load_core_window.h \
ui/drivers/qt/flowlayout.h
DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) -DHAVE_MAIN DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) -DHAVE_MAIN
#DEFINES += $(QT5WEBENGINE_CFLAGS) #DEFINES += $(QT5WEBENGINE_CFLAGS)

View File

@ -60,6 +60,8 @@ FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
{ {
setContentsMargins(margin, margin, margin, margin); setContentsMargins(margin, margin, margin, margin);
connect(this, SIGNAL(signalAddWidgetDeferred(QWidget*)), this, SLOT(onAddWidgetDeferred(QWidget*)), Qt::QueuedConnection);
} }
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
@ -70,9 +72,9 @@ FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
FlowLayout::~FlowLayout() FlowLayout::~FlowLayout()
{ {
QLayoutItem *item; QLayoutItem *item = NULL;
while ((item = takeAt(0))) while ((item = takeAt(0)) != NULL)
delete item; delete item;
} }
@ -229,3 +231,13 @@ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
else else
return static_cast<const QLayout*>(parentObj)->spacing(); return static_cast<const QLayout*>(parentObj)->spacing();
} }
void FlowLayout::addWidgetDeferred(QWidget *widget)
{
emit signalAddWidgetDeferred(widget);
}
void FlowLayout::onAddWidgetDeferred(QWidget *widget)
{
addWidget(widget);
}

View File

@ -65,6 +65,7 @@
class FlowLayout : public QLayout class FlowLayout : public QLayout
{ {
Q_OBJECT
public: public:
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
@ -82,6 +83,13 @@ public:
void setGeometry(const QRect &rect); void setGeometry(const QRect &rect);
QSize sizeHint() const; QSize sizeHint() const;
QLayoutItem* takeAt(int index); QLayoutItem* takeAt(int index);
void addWidgetDeferred(QWidget *widget);
signals:
void signalAddWidgetDeferred(QWidget *widget);
private slots:
void onAddWidgetDeferred(QWidget *widget);
private: private:
int doLayout(const QRect &rect, bool testOnly) const; int doLayout(const QRect &rect, bool testOnly) const;

View File

@ -111,6 +111,10 @@ static void scan_finished_handler(void *task_data, void *user_data, const char *
menu_environ.type = MENU_ENVIRON_RESET_HORIZONTAL_LIST; menu_environ.type = MENU_ENVIRON_RESET_HORIZONTAL_LIST;
menu_environ.data = NULL; menu_environ.data = NULL;
(void)task_data;
(void)user_data;
(void)err;
menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ); menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
if (!ui_window.qtWindow->settings()->value("scan_finish_confirm", true).toBool()) if (!ui_window.qtWindow->settings()->value("scan_finish_confirm", true).toBool())
@ -128,7 +132,6 @@ GridItem::GridItem() :
,image() ,image()
,pixmap() ,pixmap()
,imageWatcher() ,imageWatcher()
,mutex()
{ {
} }
@ -740,7 +743,6 @@ MainWindow::~MainWindow()
inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue) inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue)
{ {
QMutexLocker lock(&item->mutex);
int newSize = 0; int newSize = 0;
if (zoomValue < 50) if (zoomValue < 50)
@ -850,12 +852,12 @@ void MainWindow::setCustomThemeString(QString qss)
bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowModality modality) bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowModality modality)
{ {
QScopedPointer<QMessageBox> msgBoxPtr; QPointer<QScopedPointer<QMessageBox> > msgBoxPtr;
QMessageBox *msgBox = NULL; QMessageBox *msgBox = NULL;
QCheckBox *checkBox = NULL; QCheckBox *checkBox = NULL;
msgBoxPtr.reset(new QMessageBox(this)); msgBoxPtr.data()->reset(new QMessageBox(this));
msgBox = msgBoxPtr.data(); msgBox = msgBoxPtr.data()->data();
checkBox = new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN), msgBox); checkBox = new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN), msgBox);
msgBox->setWindowModality(modality); msgBox->setWindowModality(modality);
@ -891,6 +893,9 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM
msgBox->setText(msg); msgBox->setText(msg);
msgBox->exec(); msgBox->exec();
if (!msgBoxPtr)
return true;
if (checkBox->isChecked()) if (checkBox->isChecked())
return false; return false;
@ -904,7 +909,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
QScopedPointer<QMenu> associateMenu; QScopedPointer<QMenu> associateMenu;
QScopedPointer<QMenu> hiddenPlaylistsMenu; QScopedPointer<QMenu> hiddenPlaylistsMenu;
QScopedPointer<QAction> hideAction; QScopedPointer<QAction> hideAction;
QAction *selectedAction = NULL; QPointer<QAction> selectedAction;
QPoint cursorPos = QCursor::pos(); QPoint cursorPos = QCursor::pos();
QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos)); QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos));
QDir playlistDir(settings->paths.directory_playlist); QDir playlistDir(settings->paths.directory_playlist);
@ -1103,7 +1108,7 @@ end:
void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&) void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&)
{ {
#ifdef HAVE_LIBRETRODB #ifdef HAVE_LIBRETRODB
QAction *action = NULL; QPointer<QAction> action;
QList<QAction*> actions; QList<QAction*> actions;
QScopedPointer<QAction> scanAction; QScopedPointer<QAction> scanAction;
QDir dir; QDir dir;
@ -1153,6 +1158,8 @@ void MainWindow::onGotStatusMessage(QString msg, unsigned priority, unsigned dur
QScreen *screen = qApp->primaryScreen(); QScreen *screen = qApp->primaryScreen();
QStatusBar *status = statusBar(); QStatusBar *status = statusBar();
Q_UNUSED(priority)
if (msg.isEmpty()) if (msg.isEmpty())
return; return;
@ -2831,23 +2838,21 @@ void MainWindow::removeGridItems()
{ {
QMutableListIterator<GridItem*> items(m_gridItems); QMutableListIterator<GridItem*> items(m_gridItems);
m_pendingItemUpdates.clear();
while (items.hasNext()) while (items.hasNext())
{ {
GridItem *item = items.next(); GridItem *item = items.next();
if (item) if (item)
{ {
item->mutex.lock(); item->imageWatcher.waitForFinished();
items.remove(); items.remove();
m_gridLayout->removeWidget(item->widget); m_gridLayout->removeWidget(item->widget);
m_pendingItemUpdates.removeAll(item);
delete item->widget; delete item->widget;
item->mutex.unlock();
delete item; delete item;
} }
} }
@ -2867,15 +2872,14 @@ void MainWindow::onDeferredImageLoaded()
if (!item) if (!item)
return; return;
item->mutex.lock(); if (m_gridItems.contains(item))
if (!item->image.isNull())
{ {
m_pendingItemUpdates.append(item); if (!item->image.isNull())
QTimer::singleShot(0, this, SLOT(onPendingItemUpdates())); {
m_pendingItemUpdates.append(item);
QTimer::singleShot(0, this, SLOT(onPendingItemUpdates()));
}
} }
item->mutex.unlock();
} }
void MainWindow::onPendingItemUpdates() void MainWindow::onPendingItemUpdates()
@ -2889,7 +2893,8 @@ void MainWindow::onPendingItemUpdates()
if (!item) if (!item)
continue; continue;
onUpdateGridItemPixmapFromImage(item); if (m_gridItems.contains(item))
onUpdateGridItemPixmapFromImage(item);
list.remove(); list.remove();
} }
@ -2900,6 +2905,9 @@ void MainWindow::onUpdateGridItemPixmapFromImage(GridItem *item)
if (!item) if (!item)
return; return;
if (!m_gridItems.contains(item))
return;
item->label->setPixmap(QPixmap::fromImage(item->image)); item->label->setPixmap(QPixmap::fromImage(item->image));
item->label->update(); item->label->update();
} }
@ -2916,12 +2924,11 @@ GridItem* MainWindow::doDeferredImageLoad(GridItem *item, QString path)
if (!item) if (!item)
return NULL; return NULL;
item->mutex.lock(); /* While we are indeed writing across thread boundaries here, the image is never accessed until after
* its thread finishes, and the item is never deleted without first waiting for the thread to finish.
*/
item->image = QImage(path); item->image = QImage(path);
item->mutex.unlock();
return item; return item;
} }
@ -2992,12 +2999,10 @@ void MainWindow::addPlaylistItemsToGrid(const QString &pathString)
item->widget->layout()->addWidget(newLabel); item->widget->layout()->addWidget(newLabel);
qobject_cast<QVBoxLayout*>(item->widget->layout())->setStretchFactor(label, 1); qobject_cast<QVBoxLayout*>(item->widget->layout())->setStretchFactor(label, 1);
m_gridLayout->addWidget(item->widget); m_gridLayout->addWidgetDeferred(item->widget);
m_gridItems.append(item); m_gridItems.append(item);
loadImageDeferred(item, imagePath); loadImageDeferred(item, imagePath);
qApp->processEvents();
} }
} }
@ -3178,12 +3183,6 @@ void MainWindow::addPlaylistItemsToTable(QString pathString)
for (i = 0; i < items.count(); i++) for (i = 0; i < items.count(); i++)
{ {
const char *path = NULL;
const char *label = NULL;
const char *core_path = NULL;
const char *core_name = NULL;
const char *crc32 = NULL;
const char *db_name = NULL;
QTableWidgetItem *labelItem = NULL; QTableWidgetItem *labelItem = NULL;
const QHash<QString, QString> &hash = items.at(i); const QHash<QString, QString> &hash = items.at(i);

View File

@ -75,7 +75,6 @@ struct GridItem
QImage image; QImage image;
QPixmap pixmap; QPixmap pixmap;
QFutureWatcher<GridItem*> imageWatcher; QFutureWatcher<GridItem*> imageWatcher;
QMutex mutex;
}; };
class ThumbnailWidget : public QWidget class ThumbnailWidget : public QWidget