diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 7c80af76d..2b9fb4e33 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -422,6 +422,7 @@ rdcarray CaptureContext::GetInstalledExtensions() ext.filePath = fileinfo.absolutePath(); ext.hasChanges = m_DirtyExtensions.contains(rdcstr(package)); + ext.failedLoad = m_FailedExtensions.contains(rdcstr(package)); ext.extensionAPI = 1; if(json.contains(lit("extension_api"))) @@ -563,6 +564,7 @@ rdcstr CaptureContext::LoadExtension(rdcstr name) m_ExtensionObjects[name].swap(m_PendingExtensionObjects); m_DirtyExtensions.removeOne(name); + m_FailedExtensions.removeOne(name); for(const ExtensionMetadata &e : GetInstalledExtensions()) if(e.package == name) @@ -571,6 +573,7 @@ rdcstr CaptureContext::LoadExtension(rdcstr name) else { m_ExtensionObjects.remove(name); + m_FailedExtensions.push_back(name); for(QObject *o : m_PendingExtensionObjects) delete o; diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index d6420a2e7..ca00d4547 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -435,6 +435,7 @@ private: QList m_PendingExtensionObjects; QMap> m_ExtensionObjects; rdcarray m_DirtyExtensions; + rdcarray m_FailedExtensions; QList> m_RegisteredMenuItems; diff --git a/qrenderdoc/Code/Interface/Extensions.h b/qrenderdoc/Code/Interface/Extensions.h index 7c583c603..85452db7b 100644 --- a/qrenderdoc/Code/Interface/Extensions.h +++ b/qrenderdoc/Code/Interface/Extensions.h @@ -370,6 +370,14 @@ This will always be false if the extension is unloaded. :type: bool )"); bool hasChanges = false; + + DOCUMENT(R"(A flag indicating that the extension failed to load properly. + +This will always be false if the extension is unloaded. + +:type: bool +)"); + bool failedLoad = false; }; DECLARE_REFLECTION_STRUCT(ExtensionMetadata); diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index 935b0b3b4..75fc7fff8 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -1423,9 +1423,10 @@ QString PythonContext::LoadExtension(ICaptureContext &ctx, const rdcstr &extensi if(!valueStr.isEmpty()) { - qCritical("Error importing extension module. %s: %s", typeStr.toUtf8().data(), - valueStr.toUtf8().data()); - ret += tr("Error importing extension module. %1: %2\n\n").arg(typeStr).arg(valueStr); + qCritical("Error importing extension module '%s'. %s: %s", extension.c_str(), + typeStr.toUtf8().data(), valueStr.toUtf8().data()); + ret += + tr("Error importing extension module '%1'. %2: %3\n\n").arg(extension).arg(typeStr).arg(valueStr); if(!frames.isEmpty()) { @@ -1443,7 +1444,7 @@ QString PythonContext::LoadExtension(ICaptureContext &ctx, const rdcstr &extensi } } - if(!ret.isEmpty() && reload) + if(!ret.isEmpty()) m_ExtensionContext->addText(extension, true, ret); } diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 7af7c2544..2bad07c72 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -248,7 +248,7 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai QObject::connect(extensionReload, &RDToolButton::clicked, [this]() { rdcarray exts = m_Ctx.Extensions().GetInstalledExtensions(); for(const ExtensionMetadata &m : exts) - if(m.hasChanges) + if(m.hasChanges || m.failedLoad) m_Ctx.Extensions().LoadExtension(m.package); }); QObject::connect(PythonContext::GetExtensionContext(), &PythonContext::extensionLoaded, this, @@ -1358,6 +1358,15 @@ void MainWindow::PythonStatusUpdate() break; } } + for(const ExtensionMetadata &m : m_Ctx.Extensions().GetInstalledExtensions()) + { + if(m.failedLoad) + { + text += tr(" (some failed to load)"); + reloadVisible = true; + break; + } + } extensionReload->setVisible(reloadVisible); if(PythonContext::IsDebuggerConnected()) diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index d5d0a54ae..bc34f9af6 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -476,6 +476,11 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent) updateRecentFiles(false); updateExtensionProjects(); + // on first launch we could be creating the python shell before extensions are loaded while + // initialising the UI. Refresh the extension projects after a short delay to pick up any + // additional information on loading status. + QTimer::singleShot(200, [this]() { updateExtensionProjects(); }); + ui->projectExplorer->endUpdate(); ui->projectExplorer->expandItem(m_RecentFiles); @@ -729,12 +734,18 @@ void PythonShell::updateExtensionProjects() if(ext.hasChanges) name += tr(" (Reload required)"); + if(ext.failedLoad) + name += tr(" (Failed to load)"); + RDTreeWidgetItem *root = new RDTreeWidgetItem({name}); root->setData(0, Qt::UserRole + 1, ext.package); if(ext.hasChanges) root->setItalic(true); + if(m_Ctx.Config().AlwaysLoad_Extensions.contains(ext.package)) + root->setBold(true); + addExtensionDirItems(root, QDir(ext.filePath)); m_UIExtensions->addChild(root); @@ -1949,7 +1960,7 @@ void PythonShell::projectExplorer_contextMenu(const QPoint &pos) { if(m.package == rdcstr(itemPath)) { - reloadExtension.setEnabled(m.hasChanges); + reloadExtension.setEnabled(m.hasChanges || m.failedLoad); diskLocation = QFileInfo(m.filePath).absoluteFilePath(); break; }