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
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 += $(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)
{
setContentsMargins(margin, margin, margin, margin);
connect(this, SIGNAL(signalAddWidgetDeferred(QWidget*)), this, SLOT(onAddWidgetDeferred(QWidget*)), Qt::QueuedConnection);
}
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
@ -70,9 +72,9 @@ FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
FlowLayout::~FlowLayout()
{
QLayoutItem *item;
QLayoutItem *item = NULL;
while ((item = takeAt(0)))
while ((item = takeAt(0)) != NULL)
delete item;
}
@ -229,3 +231,13 @@ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
else
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
{
Q_OBJECT
public:
explicit FlowLayout(QWidget *parent, 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);
QSize sizeHint() const;
QLayoutItem* takeAt(int index);
void addWidgetDeferred(QWidget *widget);
signals:
void signalAddWidgetDeferred(QWidget *widget);
private slots:
void onAddWidgetDeferred(QWidget *widget);
private:
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.data = NULL;
(void)task_data;
(void)user_data;
(void)err;
menu_driver_ctl(RARCH_MENU_CTL_ENVIRONMENT, &menu_environ);
if (!ui_window.qtWindow->settings()->value("scan_finish_confirm", true).toBool())
@ -128,7 +132,6 @@ GridItem::GridItem() :
,image()
,pixmap()
,imageWatcher()
,mutex()
{
}
@ -740,7 +743,6 @@ MainWindow::~MainWindow()
inline void MainWindow::calcGridItemSize(GridItem *item, int zoomValue)
{
QMutexLocker lock(&item->mutex);
int newSize = 0;
if (zoomValue < 50)
@ -850,12 +852,12 @@ void MainWindow::setCustomThemeString(QString qss)
bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowModality modality)
{
QScopedPointer<QMessageBox> msgBoxPtr;
QPointer<QScopedPointer<QMessageBox> > msgBoxPtr;
QMessageBox *msgBox = NULL;
QCheckBox *checkBox = NULL;
msgBoxPtr.reset(new QMessageBox(this));
msgBox = msgBoxPtr.data();
msgBoxPtr.data()->reset(new QMessageBox(this));
msgBox = msgBoxPtr.data()->data();
checkBox = new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DONT_SHOW_AGAIN), msgBox);
msgBox->setWindowModality(modality);
@ -891,6 +893,9 @@ bool MainWindow::showMessageBox(QString msg, MessageBoxType msgType, Qt::WindowM
msgBox->setText(msg);
msgBox->exec();
if (!msgBoxPtr)
return true;
if (checkBox->isChecked())
return false;
@ -904,7 +909,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&)
QScopedPointer<QMenu> associateMenu;
QScopedPointer<QMenu> hiddenPlaylistsMenu;
QScopedPointer<QAction> hideAction;
QAction *selectedAction = NULL;
QPointer<QAction> selectedAction;
QPoint cursorPos = QCursor::pos();
QListWidgetItem *selectedItem = m_listWidget->itemAt(m_listWidget->viewport()->mapFromGlobal(cursorPos));
QDir playlistDir(settings->paths.directory_playlist);
@ -1103,7 +1108,7 @@ end:
void MainWindow::onFileBrowserTreeContextMenuRequested(const QPoint&)
{
#ifdef HAVE_LIBRETRODB
QAction *action = NULL;
QPointer<QAction> action;
QList<QAction*> actions;
QScopedPointer<QAction> scanAction;
QDir dir;
@ -1153,6 +1158,8 @@ void MainWindow::onGotStatusMessage(QString msg, unsigned priority, unsigned dur
QScreen *screen = qApp->primaryScreen();
QStatusBar *status = statusBar();
Q_UNUSED(priority)
if (msg.isEmpty())
return;
@ -2831,23 +2838,21 @@ void MainWindow::removeGridItems()
{
QMutableListIterator<GridItem*> items(m_gridItems);
m_pendingItemUpdates.clear();
while (items.hasNext())
{
GridItem *item = items.next();
if (item)
{
item->mutex.lock();
item->imageWatcher.waitForFinished();
items.remove();
m_gridLayout->removeWidget(item->widget);
m_pendingItemUpdates.removeAll(item);
delete item->widget;
item->mutex.unlock();
delete item;
}
}
@ -2867,15 +2872,14 @@ void MainWindow::onDeferredImageLoaded()
if (!item)
return;
item->mutex.lock();
if (!item->image.isNull())
if (m_gridItems.contains(item))
{
m_pendingItemUpdates.append(item);
QTimer::singleShot(0, this, SLOT(onPendingItemUpdates()));
if (!item->image.isNull())
{
m_pendingItemUpdates.append(item);
QTimer::singleShot(0, this, SLOT(onPendingItemUpdates()));
}
}
item->mutex.unlock();
}
void MainWindow::onPendingItemUpdates()
@ -2889,7 +2893,8 @@ void MainWindow::onPendingItemUpdates()
if (!item)
continue;
onUpdateGridItemPixmapFromImage(item);
if (m_gridItems.contains(item))
onUpdateGridItemPixmapFromImage(item);
list.remove();
}
@ -2900,6 +2905,9 @@ void MainWindow::onUpdateGridItemPixmapFromImage(GridItem *item)
if (!item)
return;
if (!m_gridItems.contains(item))
return;
item->label->setPixmap(QPixmap::fromImage(item->image));
item->label->update();
}
@ -2916,12 +2924,11 @@ GridItem* MainWindow::doDeferredImageLoad(GridItem *item, QString path)
if (!item)
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->mutex.unlock();
return item;
}
@ -2992,12 +2999,10 @@ void MainWindow::addPlaylistItemsToGrid(const QString &pathString)
item->widget->layout()->addWidget(newLabel);
qobject_cast<QVBoxLayout*>(item->widget->layout())->setStretchFactor(label, 1);
m_gridLayout->addWidget(item->widget);
m_gridLayout->addWidgetDeferred(item->widget);
m_gridItems.append(item);
loadImageDeferred(item, imagePath);
qApp->processEvents();
}
}
@ -3178,12 +3183,6 @@ void MainWindow::addPlaylistItemsToTable(QString pathString)
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;
const QHash<QString, QString> &hash = items.at(i);

View File

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