Add update checking system to Qt UI

* This only runs on windows - on other platforms we rely on system
  distribution or user local builds.
This commit is contained in:
baldurk
2017-12-19 17:31:32 +00:00
parent 08c67f2149
commit 764b39a23c
16 changed files with 1283 additions and 50 deletions
+71
View File
@@ -26,6 +26,7 @@
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QElapsedTimer>
#include <QElapsedTimer>
#include <QFileSystemModel>
#include <QFontDatabase>
#include <QGridLayout>
@@ -38,6 +39,7 @@
#include <QMouseEvent>
#include <QPainter>
#include <QProcess>
#include <QProgressBar>
#include <QProgressDialog>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
@@ -1558,6 +1560,75 @@ void ShowProgressDialog(QWidget *window, const QString &labelText, ProgressFinis
progressTickerThread.wait();
}
void UpdateTransferProgress(qint64 xfer, qint64 total, QElapsedTimer *timer,
QProgressBar *progressBar, QLabel *progressLabel, QString progressText)
{
if(xfer >= total)
{
progressBar->setMaximum(10000);
progressBar->setValue(10000);
return;
}
if(total <= 0)
{
progressBar->setMaximum(10000);
progressBar->setValue(0);
return;
}
progressBar->setMaximum(10000);
progressBar->setValue(int(10000.0 * (double(xfer) / double(total))));
double xferMB = double(xfer) / 1000000.0;
double totalMB = double(total) / 1000000.0;
double secondsElapsed = double(timer->nsecsElapsed()) * 1.0e-9;
double speedMBS = xferMB / secondsElapsed;
qulonglong secondsRemaining = qulonglong(double(totalMB - xferMB) / speedMBS);
if(secondsElapsed > 1.0)
{
QString remainString;
qulonglong minutesRemaining = (secondsRemaining / 60) % 60;
qulonglong hoursRemaining = (secondsRemaining / 3600);
secondsRemaining %= 60;
if(hoursRemaining > 0)
remainString = QFormatStr("%1:%2:%3")
.arg(hoursRemaining, 2, 10, QLatin1Char('0'))
.arg(minutesRemaining, 2, 10, QLatin1Char('0'))
.arg(secondsRemaining, 2, 10, QLatin1Char('0'));
else if(minutesRemaining > 0)
remainString = QFormatStr("%1:%2")
.arg(minutesRemaining, 2, 10, QLatin1Char('0'))
.arg(secondsRemaining, 2, 10, QLatin1Char('0'));
else
remainString = QApplication::translate("qrenderdoc", "%1 seconds").arg(secondsRemaining);
double speed = speedMBS;
bool MBs = true;
if(speedMBS < 1)
{
MBs = false;
speed *= 1000;
}
progressLabel->setText(
QApplication::translate("qrenderdoc", "%1\n%2 MB / %3 MB. %4 remaining (%5 %6)")
.arg(progressText)
.arg(xferMB, 0, 'f', 2)
.arg(totalMB, 0, 'f', 2)
.arg(remainString)
.arg(speed, 0, 'f', 2)
.arg(MBs ? lit("MB/s") : lit("KB/s")));
}
}
void setEnabledMultiple(const QList<QWidget *> &widgets, bool enabled)
{
for(QWidget *w : widgets)
+5
View File
@@ -515,6 +515,8 @@ class QGridLayout;
void addGridLines(QGridLayout *grid, QColor gridColor);
class QProgressDialog;
class QProgressBar;
class QElapsedTimer;
typedef std::function<float()> ProgressUpdateMethod;
typedef std::function<bool()> ProgressFinishedMethod;
@@ -527,6 +529,9 @@ bool RunProcessAsAdmin(const QString &fullExecutablePath, const QStringList &par
void ShowProgressDialog(QWidget *window, const QString &labelText, ProgressFinishedMethod finished,
ProgressUpdateMethod update = ProgressUpdateMethod());
void UpdateTransferProgress(qint64 xfer, qint64 total, QElapsedTimer *timer,
QProgressBar *progressBar, QLabel *progressLabel, QString progressText);
void setEnabledMultiple(const QList<QWidget *> &widgets, bool enabled);
QString GetSystemUsername();
+30
View File
@@ -121,6 +121,29 @@ int main(int argc, char *argv[])
}
}
bool updateApplied = false;
for(int i = 0; i < argc; i++)
{
if(!QString::compare(QString::fromUtf8(argv[i]), lit("--updatefailed"), Qt::CaseInsensitive))
{
if(i < argc - 1)
RDDialog::critical(NULL, QApplication::translate("qrenderdoc", "Error updating"),
QApplication::translate("qrenderdoc", "Error applying update: %1")
.arg(QString::fromUtf8(argv[i + 1])));
else
RDDialog::critical(NULL, QApplication::translate("qrenderdoc", "Error updating"),
QApplication::translate("qrenderdoc", "Unknown error applying update"));
}
if(!QString::compare(QString::fromUtf8(argv[i]), lit("--updatedone"), Qt::CaseInsensitive))
{
updateApplied = true;
RENDERDOC_UpdateInstalledVersionNumber();
}
}
QString remoteHost;
uint remoteIdent = 0;
@@ -327,6 +350,13 @@ int main(int argc, char *argv[])
}
}
if(updateApplied)
{
config.CheckUpdate_UpdateAvailable = false;
config.CheckUpdate_UpdateResponse = "";
config.Save();
}
while(ctx.isRunning())
{
application.processEvents(QEventLoop::WaitForMoreEvents);
+7 -46
View File
@@ -144,7 +144,6 @@ void CrashDialog::resizeEvent(QResizeEvent *)
{
recentre();
}
void CrashDialog::recentre()
{
QRect scr = QApplication::desktop()->screenGeometry();
@@ -187,10 +186,11 @@ void CrashDialog::on_send_clicked()
if(ui->captureUpload->isChecked())
{
QMessageBox::StandardButton result = RDDialog::question(
this, tr("Are you sure?"),
tr("Uploading your capture file will send it privately to the RenderDoc server where I can "
"use it to reproduce your problem.\n\nAre you sure you are OK with sending the capture "
"securely to RenderDoc's website?"));
this, tr("Are you sure?"), tr("Uploading your capture file will send it privately to the "
"RenderDoc server where I can "
"use it to reproduce your problem.\n\nAre you sure you are "
"OK with sending the capture "
"securely to RenderDoc's website?"));
if(result != QMessageBox::Yes)
{
@@ -334,7 +334,6 @@ void CrashDialog::sendReport()
ui->uploadRetry->setEnabled(true);
});
ui->progressBar->setMaximum(10000);
ui->progressBar->setValue(0);
ui->progressText->setText(tr("Uploading report...\nCalculating time remaining"));
@@ -344,46 +343,8 @@ void CrashDialog::sendReport()
m_UploadTimer->start();
QObject::connect(m_Request, &QNetworkReply::uploadProgress, [this](qint64 sent, qint64 total) {
if(total > 0 && total > sent)
{
ui->progressBar->setValue(int(10000.0 * (double(sent) / double(total))));
double sentMB = double(sent) / 1000000.0;
double totalMB = double(total) / 1000000.0;
double secondsElapsed = double(m_UploadTimer->nsecsElapsed()) * 1.0e-9;
double speedMBS = sentMB / secondsElapsed;
qulonglong secondsRemaining = qulonglong(double(totalMB - sentMB) / speedMBS);
if(secondsElapsed > 1.0)
{
QString remainString;
qulonglong minutesRemaining = (secondsRemaining / 60) % 60;
qulonglong hoursRemaining = (secondsRemaining / 3600);
secondsRemaining %= 60;
if(hoursRemaining > 0)
remainString = QFormatStr("%1:%2:%3")
.arg(hoursRemaining, 2, 10, QLatin1Char('0'))
.arg(minutesRemaining, 2, 10, QLatin1Char('0'))
.arg(secondsRemaining, 2, 10, QLatin1Char('0'));
else if(minutesRemaining > 0)
remainString = QFormatStr("%1:%2")
.arg(minutesRemaining, 2, 10, QLatin1Char('0'))
.arg(secondsRemaining, 2, 10, QLatin1Char('0'));
else
remainString = tr("%1 seconds").arg(secondsRemaining);
ui->progressText->setText(tr("Uploading report...\n%1 MB / %2 MB. %3 remaining (%4 MB/s)")
.arg(sentMB, 0, 'f', 2)
.arg(totalMB, 0, 'f', 2)
.arg(remainString)
.arg(speedMBS, 0, 'f', 2));
}
}
UpdateTransferProgress(sent, total, m_UploadTimer, ui->progressBar, ui->progressText,
tr("Uploading report..."));
});
QObject::connect(m_Request, &QNetworkReply::finished, [this]() {
@@ -222,6 +222,12 @@ void SettingsDialog::on_CheckUpdate_AllowChecks_toggled(bool checked)
{
m_Ctx.Config().CheckUpdate_AllowChecks = ui->CheckUpdate_AllowChecks->isChecked();
if(!m_Ctx.Config().CheckUpdate_AllowChecks)
{
m_Ctx.Config().CheckUpdate_UpdateAvailable = false;
m_Ctx.Config().CheckUpdate_UpdateResponse = "";
}
m_Ctx.Config().Save();
}
+263
View File
@@ -0,0 +1,263 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "UpdateDialog.h"
#include <QApplication>
#include <QCloseEvent>
#include <QDateTime>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QLabel>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QString>
#include "Code/QRDUtils.h"
#include "ui_UpdateDialog.h"
#include "version.h"
UpdateDialog::UpdateDialog(QString updateResponse, QWidget *parent)
: QDialog(parent), ui(new Ui::UpdateDialog)
{
ui->setupUi(this);
ui->updateText->setBackgroundRole(QPalette::Base);
ui->updateText->setForegroundRole(QPalette::Text);
m_NetManager = new QNetworkAccessManager(this);
setWindowFlags((windowFlags() | Qt::MSWindowsFixedSizeDialogHint) &
~Qt::WindowContextHelpButtonHint);
QStringList lines = updateResponse.split(QLatin1Char('\n'), QString::SkipEmptyParts);
m_NewVer = lines[0];
m_URL = lines[1];
m_Size = lines[2].toUInt();
QString notes;
for(int i = 3; i < lines.count(); i++)
notes += lines[i];
ui->progressText->setVisible(false);
ui->progressBar->setVisible(false);
QString text = tr("Update Available - v%1").arg(m_NewVer);
ui->updateVer->setText(text);
setWindowTitle(text);
ui->updateText->setText(notes);
ui->currentVersion->setText(lit(FULL_VERSION_STRING));
ui->newVersion->setText(QFormatStr("v%1").arg(m_NewVer));
ui->downloadSize->setText(QFormatStr("%1 MB").arg(double(m_Size) / 1000000.0, 0, 'f', 2));
adjustSize();
}
UpdateDialog::~UpdateDialog()
{
delete m_DownloadTimer;
delete ui;
}
void UpdateDialog::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Escape)
return;
QDialog::keyPressEvent(e);
}
void UpdateDialog::closeEvent(QCloseEvent *e)
{
if(ui->close->isEnabled())
{
QDialog::closeEvent(e);
return;
}
e->ignore();
return;
}
void UpdateDialog::on_releaseNotes_clicked()
{
QDesktopServices::openUrl(
QUrl(lit("https://github.com/baldurk/renderdoc/releases/tag/v%1").arg(m_NewVer)));
}
void UpdateDialog::on_close_clicked()
{
reject();
}
void UpdateDialog::on_update_clicked()
{
QMessageBox::StandardButton res = RDDialog::question(
this, tr("RenderDoc Update"), tr("This will close RenderDoc immediately - if you have any "
"unsaved work, save it first!\n"
"Continue?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if(res == QMessageBox::Yes)
{
QString runningPrograms;
int running = 0;
uint32_t nextIdent = 0;
QString localhost = lit("localhost");
for(;;)
{
// just a sanity check to make sure we don't hit some unexpected case and infinite loop
uint32_t prevIdent = nextIdent;
nextIdent = RENDERDOC_EnumerateRemoteTargets("localhost", nextIdent);
if(nextIdent == 0 || prevIdent >= nextIdent)
break;
running++;
ITargetControl *conn = RENDERDOC_CreateTargetControl("localhost", nextIdent, "updater", false);
if(conn)
{
if(!runningPrograms.isEmpty())
runningPrograms += lit("\n");
QString target =
conn->GetTarget() ? QString::fromUtf8(conn->GetTarget()) : lit("<unknown>");
if(conn->GetAPI())
runningPrograms += tr("%1 running %2").arg(target).arg(QString::fromUtf8(conn->GetAPI()));
else
runningPrograms += target;
conn->Shutdown();
}
}
if(running > 0)
{
RDDialog::critical(
this, tr("RenderDoc in use"),
tr("RenderDoc is currently capturing, cannot update until the program%1 closed:\n\n")
.arg(running > 1 ? lit("s are") : lit(" is")) +
runningPrograms);
return;
}
ui->metadataFrame->setVisible(false);
ui->progressBar->setVisible(true);
ui->progressText->setVisible(true);
ui->progressBar->setMaximum(10000);
ui->progressBar->setValue(0);
ui->progressText->setText(tr("Preparing Download"));
ui->close->setEnabled(false);
ui->update->setEnabled(false);
delete m_DownloadTimer;
m_DownloadTimer = new QElapsedTimer();
m_DownloadTimer->start();
QNetworkReply *req = m_NetManager->get(QNetworkRequest(QUrl(m_URL)));
QObject::connect(req, &QNetworkReply::downloadProgress, [this](qint64 recvd, qint64 total) {
UpdateTransferProgress(recvd, total, m_DownloadTimer, ui->progressBar, ui->progressText,
tr("Downloading update..."));
});
QObject::connect(req, OverloadedSlot<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
[this, req](QNetworkReply::NetworkError err) {
ui->progressBar->setValue(0);
ui->progressText->setText(tr("Network error:\n%1").arg(req->errorString()));
ui->update->setEnabled(true);
ui->close->setEnabled(true);
ui->update->setText(tr("Retry Update"));
});
QObject::connect(req, &QNetworkReply::finished, [this, req]() {
// don't do anything if we're finished after an error
if(ui->update->isEnabled())
return;
QDir dir(QDir::tempPath());
dir.mkdir(lit("RenderDocUpdate"));
dir.cd(lit("RenderDocUpdate"));
QString path = dir.absoluteFilePath(lit("update.zip"));
{
QFile file(path);
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
file.write(req->readAll());
}
else
{
RDDialog::critical(this, tr("Error saving file"),
tr("Couldn't save update file to: %1").arg(path));
reject();
}
}
QDir appDir = QFileInfo(QCoreApplication::applicationFilePath()).absoluteDir();
bool success = true;
QString dll = lit("renderdoc.dll");
QString cmd = lit("renderdoccmd.exe");
QFile::remove(dir.absoluteFilePath(dll));
QFile::remove(dir.absoluteFilePath(cmd));
success &= QFile::copy(appDir.absoluteFilePath(dll), dir.absoluteFilePath(dll));
success &= QFile::copy(appDir.absoluteFilePath(cmd), dir.absoluteFilePath(cmd));
if(!success)
{
RDDialog::critical(this, tr("Error running updated"),
tr("Couldn't copy updater files to temporary path"));
reject();
}
QDir::setCurrent(dir.absolutePath());
success = RunProcessAsAdmin(dir.absoluteFilePath(cmd), QStringList()
<< lit("upgrade") << lit("--path")
<< appDir.absolutePath());
exit(0);
});
}
}
+67
View File
@@ -0,0 +1,67 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <QDialog>
namespace Ui
{
class UpdateDialog;
}
class QNetworkAccessManager;
class QNetworkReply;
class QElapsedTimer;
struct Thumbnail;
class UpdateDialog : public QDialog
{
Q_OBJECT
public:
explicit UpdateDialog(QString updateResponse, QWidget *parent = 0);
~UpdateDialog();
private slots:
// automatic slots
void on_releaseNotes_clicked();
void on_close_clicked();
void on_update_clicked();
private:
void keyPressEvent(QKeyEvent *e) override;
void closeEvent(QCloseEvent *) override;
QString m_NewVer;
QString m_URL;
uint32_t m_Size = 0;
Ui::UpdateDialog *ui;
QElapsedTimer *m_DownloadTimer = NULL;
QNetworkAccessManager *m_NetManager;
QNetworkReply *m_Request = NULL;
};
+423
View File
@@ -0,0 +1,423 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UpdateDialog</class>
<widget class="QDialog" name="UpdateDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>465</width>
<height>505</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Update Available</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>59</red>
<green>183</green>
<blue>121</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>59</red>
<green>183</green>
<blue>121</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>106</red>
<green>104</green>
<blue>100</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>59</red>
<green>183</green>
<blue>121</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>59</red>
<green>183</green>
<blue>121</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>20</number>
</property>
<property name="rightMargin">
<number>20</number>
</property>
<item>
<widget class="RDLabel" name="rdocLogo">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../Resources/resources.qrc">:/logo.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="updateVer">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active/>
<inactive/>
<disabled/>
</palette>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="text">
<string>Update Available - vX.YZ</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>12</number>
</property>
<item>
<widget class="RDLabel" name="updateText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>200</height>
</size>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>6</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="metadataFrame">
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>10</number>
</property>
<item row="1" column="1">
<widget class="QLabel" name="newLabel">
<property name="text">
<string>New Version:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="sizeLabel">
<property name="text">
<string>Download Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="currentVersion">
<property name="text">
<string>vX.YY</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QLabel" name="newVersion">
<property name="text">
<string>vX.YZ</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="downloadSize">
<property name="text">
<string>12.34 MB</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="curLabel">
<property name="text">
<string>Current Version:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="progressText">
<property name="text">
<string>Downloading</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar"/>
</item>
<item>
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="releaseNotes">
<property name="text">
<string>Full Release Notes</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="update">
<property name="text">
<string>Install Update</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>RDLabel</class>
<extends>QLabel</extends>
<header>Widgets/Extended/RDLabel.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../Resources/resources.qrc"/>
</resources>
<connections/>
</ui>
+249 -3
View File
@@ -47,6 +47,7 @@
#include "Windows/Dialogs/SettingsDialog.h"
#include "Windows/Dialogs/SuggestRemoteDialog.h"
#include "Windows/Dialogs/TipsDialog.h"
#include "Windows/Dialogs/UpdateDialog.h"
#include "ui_MainWindow.h"
#include "version.h"
@@ -180,11 +181,30 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
ui->action_Send_Error_Report->setEnabled(false);
#endif
m_NetManager = new QNetworkAccessManager(this);
#if !defined(Q_OS_WIN32)
// update checks only happen on windows
{
QList<QAction *> actions = ui->menu_Help->actions();
int idx = actions.indexOf(ui->action_Update_Available);
idx++;
if(idx < actions.count() && actions[idx]->isSeparator())
delete actions[idx];
delete ui->action_Update_Available;
ui->action_Update_Available = NULL;
delete ui->action_Check_for_Updates;
ui->action_Check_for_Updates = NULL;
}
#endif
PopulateRecentCaptureFiles();
PopulateRecentCaptureSettings();
PopulateReportedBugs();
m_NetManager = new QNetworkAccessManager(this);
CheckUpdates();
rdcarray<BugReport> bugs = m_Ctx.Config().CrashReport_ReportedBugs;
LambdaThread *bugupdate = new LambdaThread([this, bugs]() {
@@ -854,6 +874,47 @@ void MainWindow::SetTitle()
SetTitle(m_Ctx.GetCaptureFilename());
}
bool MainWindow::HandleMismatchedVersions()
{
if(IsVersionMismatched())
{
qCritical() << "Version mismatch between UI (" << lit(MAJOR_MINOR_VERSION_STRING) << ")"
<< "and core"
<< "(" << QString::fromUtf8(RENDERDOC_GetVersionString()) << ")";
#if !RENDERDOC_OFFICIAL_BUILD
RDDialog::critical(
this, tr("Unofficial build - mismatched versions"),
tr("You are running an unofficial build with mismatched core and UI versions.\n"
"Double check where you got your build from and do a sanity check!"));
#else
QMessageBox::StandardButton res = RDDialog::critical(
this, tr("Mismatched versions"),
tr("RenderDoc has detected mismatched versions between its internal module and UI.\n"
"This is likely caused by a buggy update in the past which partially updated your "
"install."
"Likely because a program was running with renderdoc while the update happened.\n"
"You should reinstall RenderDoc immediately as this configuration is almost guaranteed "
"to crash.\n\n"
"Would you like to open the downloads page to reinstall?"),
QMessageBox::Yes | QMessageBox::No);
if(res == QMessageBox::Yes)
QDesktopServices::openUrl(QUrl(lit("https://renderdoc.org/builds")));
SetUpdateAvailable();
#endif
return true;
}
return false;
}
bool MainWindow::IsVersionMismatched()
{
return QString::fromLatin1(RENDERDOC_GetVersionString()) != lit(MAJOR_MINOR_VERSION_STRING);
}
void MainWindow::ClearRecentCaptureFiles()
{
m_Ctx.Config().RecentCaptureFiles.clear();
@@ -952,16 +1013,152 @@ void MainWindow::PopulateReportedBugs()
if(unread)
{
ui->menu_Help->setIcon(Icons::bug());
if(!m_Ctx.Config().CheckUpdate_UpdateAvailable)
ui->menu_Help->setIcon(Icons::bug());
ui->menu_Reported_Bugs->setIcon(Icons::bug());
}
else
{
ui->menu_Help->setIcon(QIcon());
if(!m_Ctx.Config().CheckUpdate_UpdateAvailable)
ui->menu_Help->setIcon(QIcon());
ui->menu_Reported_Bugs->setIcon(QIcon());
}
}
void MainWindow::CheckUpdates(bool forceCheck, UpdateResultMethod callback)
{
if(!ui->action_Update_Available)
return;
bool mismatch = HandleMismatchedVersions();
if(mismatch)
return;
if(!forceCheck && !m_Ctx.Config().CheckUpdate_AllowChecks)
{
ui->action_Update_Available->setText(tr("Update checks disabled"));
ui->action_Update_Available->setEnabled(false);
if(callback)
callback(UpdateResult::Disabled);
return;
}
#if RENDERDOC_OFFICIAL_BUILD
if(m_Ctx.Config().CheckUpdate_UpdateAvailable)
{
if(m_Ctx.Config().CheckUpdate_UpdateResponse.isEmpty())
{
forceCheck = true;
}
else if(!forceCheck)
{
SetUpdateAvailable();
return;
}
}
QDateTime today = QDateTime::currentDateTime();
QDateTime compare = today.addDays(-2);
qint64 diff = compare.secsTo(m_Ctx.Config().CheckUpdate_LastUpdate);
if(!forceCheck && diff > 0)
{
if(callback)
callback(UpdateResult::Toosoon);
return;
}
m_Ctx.Config().CheckUpdate_LastUpdate = today;
m_Ctx.Config().Save();
#if QT_POINTER_SIZE == 4
QString bitness = lit("32");
#else
QString bitness = lit("64");
#endif
QString versionCheck = lit(MAJOR_MINOR_VERSION_STRING);
statusText->setText(tr("Checking for updates..."));
statusProgress->setVisible(true);
statusProgress->setMinimumSize(QSize(200, 0));
statusProgress->setMinimum(0);
statusProgress->setMaximum(0);
// call out to the status-check to see when the bug report was last updated
QNetworkReply *req = m_NetManager->get(QNetworkRequest(QUrl(
lit("https://renderdoc.org/getupdateurl/%1/%2?htmlnotes=1").arg(bitness).arg(versionCheck))));
QObject::connect(req, OverloadedSlot<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
[this, req](QNetworkReply::NetworkError) {
qCritical() << "Network error:" << req->errorString();
});
QObject::connect(req, &QNetworkReply::finished, [this, req, callback]() {
QString response = QString::fromUtf8(req->readAll());
statusText->setText(QString());
statusProgress->setVisible(false);
statusProgress->setMaximum(1000);
if(response.isEmpty())
{
m_Ctx.Config().CheckUpdate_UpdateAvailable = false;
m_Ctx.Config().CheckUpdate_UpdateResponse = "";
m_Ctx.Config().Save();
SetNoUpdate();
if(callback)
callback(UpdateResult::Latest);
return;
}
m_Ctx.Config().CheckUpdate_UpdateAvailable = true;
m_Ctx.Config().CheckUpdate_UpdateResponse = response;
m_Ctx.Config().Save();
SetUpdateAvailable();
UpdatePopup();
});
#else //! RENDERDOC_OFFICIAL_BUILD
{
if(callback)
callback(UpdateResult::Unofficial);
return;
}
#endif
}
void MainWindow::SetUpdateAvailable()
{
if(!ui->action_Update_Available)
return;
ui->menu_Help->setIcon(Icons::hourglass());
ui->action_Update_Available->setEnabled(true);
ui->action_Update_Available->setText(tr("An update is available"));
}
void MainWindow::SetNoUpdate()
{
if(!ui->action_Update_Available)
return;
ui->menu_Help->setIcon(QIcon());
ui->action_Update_Available->setEnabled(false);
ui->action_Update_Available->setText(tr("No update available"));
}
void MainWindow::UpdatePopup()
{
if(!m_Ctx.Config().CheckUpdate_UpdateAvailable || !m_Ctx.Config().CheckUpdate_AllowChecks)
return;
UpdateDialog update((QString)m_Ctx.Config().CheckUpdate_UpdateResponse);
RDDialog::show(&update);
}
void MainWindow::ShowLiveCapture(LiveCapture *live)
{
m_LiveCaptures.push_back(live);
@@ -1124,6 +1321,7 @@ void MainWindow::setProgress(float val)
else
{
statusProgress->setVisible(true);
statusProgress->setMaximum(1000);
statusProgress->setValue(1000 * val);
}
}
@@ -1972,6 +2170,54 @@ void MainWindow::on_action_Send_Error_Report_triggered()
QFile::remove(QString(report));
}
void MainWindow::on_action_Check_for_Updates_triggered()
{
CheckUpdates(true, [this](UpdateResult updateResult) {
switch(updateResult)
{
case UpdateResult::Disabled:
case UpdateResult::Toosoon:
{
// won't happen, we forced the check
break;
}
case UpdateResult::Unofficial:
{
QMessageBox::StandardButton res =
RDDialog::question(this, tr("Unofficial build"),
tr("You are running an unofficial build, not a stable release.\n"
"Updates are only available for installed release builds\n\n"
"Would you like to open the builds list in a browser?"));
if(res == QMessageBox::Yes)
QDesktopServices::openUrl(lit("https://renderdoc.org/builds"));
break;
}
case UpdateResult::Latest:
{
RDDialog::information(this, tr("Latest version"),
tr("You are running the latest version."));
break;
}
case UpdateResult::Upgrade:
{
// CheckUpdates() will have shown a dialog for this
break;
}
}
});
}
void MainWindow::on_action_Update_Available_triggered()
{
bool mismatch = HandleMismatchedVersions();
if(mismatch)
return;
SetUpdateAvailable();
UpdatePopup();
}
void MainWindow::saveLayout_triggered()
{
LoadSaveLayout(qobject_cast<QAction *>(QObject::sender()), true);
+20
View File
@@ -138,6 +138,8 @@ private slots:
void on_action_Counter_Viewer_triggered();
void on_action_Resource_Inspector_triggered();
void on_action_Send_Error_Report_triggered();
void on_action_Check_for_Updates_triggered();
void on_action_Update_Available_triggered();
// manual slots
void saveLayout_triggered();
@@ -162,6 +164,17 @@ private:
QString dragFilename(const QMimeData *mimeData);
enum class UpdateResult
{
Disabled,
Unofficial,
Toosoon,
Latest,
Upgrade,
};
typedef std::function<void(UpdateResult)> UpdateResultMethod;
Ui::MainWindow *ui;
ICaptureContext &m_Ctx;
@@ -188,6 +201,13 @@ private:
QString m_LastSaveCapturePath;
void CheckUpdates(bool forceCheck = false, UpdateResultMethod callback = UpdateResultMethod());
void SetUpdateAvailable();
void SetNoUpdate();
void UpdatePopup();
bool HandleMismatchedVersions();
bool IsVersionMismatched();
void setCaptureHasErrors(bool errors);
void SetTitle(const QString &filename);
+14 -1
View File
@@ -154,6 +154,7 @@
<addaction name="action_Send_Error_Report"/>
<addaction name="menu_Reported_Bugs"/>
<addaction name="separator"/>
<addaction name="action_Check_for_Updates"/>
<addaction name="action_Update_Available"/>
<addaction name="separator"/>
<addaction name="action_Source_on_GitHub"/>
@@ -364,8 +365,15 @@
</property>
</action>
<action name="action_Update_Available">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/hourglass.png</normaloff>:/hourglass.png</iconset>
</property>
<property name="text">
<string>Update Available</string>
<string>No update available</string>
</property>
</action>
<action name="action_Source_on_GitHub">
@@ -443,6 +451,11 @@
<string>&amp;Clear Reported Bugs</string>
</property>
</action>
<action name="action_Check_for_Updates">
<property name="text">
<string>Check for updates</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+3
View File
@@ -172,6 +172,7 @@ SOURCES += Code/qrenderdoc.cpp \
Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp \
Windows/Dialogs/AboutDialog.cpp \
Windows/Dialogs/CrashDialog.cpp \
Windows/Dialogs/UpdateDialog.cpp \
Windows/MainWindow.cpp \
Windows/EventBrowser.cpp \
Windows/TextureViewer.cpp \
@@ -244,6 +245,7 @@ HEADERS += Code/CaptureContext.h \
Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h \
Windows/Dialogs/AboutDialog.h \
Windows/Dialogs/CrashDialog.h \
Windows/Dialogs/UpdateDialog.h \
Windows/MainWindow.h \
Windows/EventBrowser.h \
Windows/TextureViewer.h \
@@ -299,6 +301,7 @@ HEADERS += Code/CaptureContext.h \
Windows/Dialogs/AnalyticsPromptDialog.h
FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/Dialogs/CrashDialog.ui \
Windows/Dialogs/UpdateDialog.ui \
Windows/MainWindow.ui \
Windows/EventBrowser.ui \
Windows/TextureViewer.ui \
+15
View File
@@ -578,6 +578,7 @@
<ClCompile Include="$(IntDir)generated\moc_RDTweakedNativeStyle.cpp" />
<ClCompile Include="$(IntDir)generated\moc_AboutDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_CrashDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_UpdateDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_AnalyticsConfirmDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_AnalyticsPromptDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_APIInspector.cpp" />
@@ -690,6 +691,7 @@
<ClCompile Include="Windows\CommentView.cpp" />
<ClCompile Include="Windows\Dialogs\AboutDialog.cpp" />
<ClCompile Include="Windows\Dialogs\CrashDialog.cpp" />
<ClCompile Include="Windows\Dialogs\UpdateDialog.cpp" />
<ClCompile Include="Windows\Dialogs\AnalyticsConfirmDialog.cpp" />
<ClCompile Include="Windows\Dialogs\AnalyticsPromptDialog.cpp" />
<ClCompile Include="Windows\Dialogs\CaptureDialog.cpp" />
@@ -888,6 +890,7 @@
<ClInclude Include="Code\Resources.h" />
<ClInclude Include="$(IntDir)generated\ui_AboutDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_CrashDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_UpdateDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_AnalyticsConfirmDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_AnalyticsPromptDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_APIInspector.h" />
@@ -1128,6 +1131,12 @@
<Message>MOC %(Filename).h</Message>
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\UpdateDialog.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp"</Command>
<Message>MOC %(Filename).h</Message>
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\AnalyticsConfirmDialog.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui" -I"$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp"</Command>
@@ -1374,6 +1383,12 @@
<Message>UIC %(Filename).ui</Message>
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\UpdateDialog.ui">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe" "%(Fullpath)" -o "$(IntDir)generated\ui_%(Filename).h"</Command>
<Message>UIC %(Filename).ui</Message>
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\AnalyticsConfirmDialog.ui">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe" "%(Fullpath)" -o "$(IntDir)generated\ui_%(Filename).h"</Command>
@@ -696,6 +696,12 @@
<ClCompile Include="Windows\Dialogs\CrashDialog.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)generated\moc_UpdateDialog.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="Windows\Dialogs\UpdateDialog.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
@@ -1049,6 +1055,9 @@
<ClInclude Include="$(IntDir)generated\ui_CrashDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="$(IntDir)generated\ui_UpdateDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Code\pyrenderdoc\pyconversion.h">
@@ -1415,6 +1424,12 @@
<CustomBuild Include="Windows\Dialogs\CrashDialog.ui">
<Filter>Windows\Dialogs</Filter>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\UpdateDialog.h">
<Filter>Windows\Dialogs</Filter>
</CustomBuild>
<CustomBuild Include="Windows\Dialogs\UpdateDialog.ui">
<Filter>Windows\Dialogs</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="Resources\action.png">
+3
View File
@@ -1876,6 +1876,9 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UpdateVulkanLayerRegistrati
// Miscellaneous!
//////////////////////////////////////////////////////////////////////////
DOCUMENT("Internal function for updating installed version number in windows registry.");
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UpdateInstalledVersionNumber();
DOCUMENT("Internal function for initialising global process environment in a replay program.");
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_InitGlobalEnv(GlobalEnvironment env,
const rdcarray<rdcstr> &args);
+92
View File
@@ -498,6 +498,98 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UpdateVulkanLayerRegistrati
RenderDoc::Inst().UpdateVulkanLayerRegistration(systemLevel);
}
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UpdateInstalledVersionNumber()
{
#if ENABLED(RDOC_WIN32)
HKEY key = NULL;
LSTATUS ret =
RegCreateKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &key, NULL);
if(ret != ERROR_SUCCESS)
{
if(key)
RegCloseKey(key);
return;
}
bool done = false;
char guidName[256] = {};
for(DWORD idx = 0; ret == ERROR_SUCCESS && !done; idx++)
{
// enumerate all the uninstall keys
ret = RegEnumKeyA(key, idx, guidName, sizeof(guidName) - 1);
if(ret == ERROR_NO_MORE_ITEMS)
{
break;
}
else if(ret != ERROR_SUCCESS)
{
break;
}
// open the key as we'll need it for RegSetValueExA
HKEY subkey = NULL;
ret = RegCreateKeyExA(key, guidName, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &subkey, NULL);
if(ret == ERROR_SUCCESS && subkey)
{
char DisplayName[256] = {};
char Publisher[256] = {};
DWORD len = sizeof(DisplayName) - 1;
// fetch DisplayName and Publisher values
ret = RegGetValueA(subkey, NULL, "DisplayName", RRF_RT_ANY, NULL, DisplayName, &len);
// allow the value to silently not exist
if(ret != ERROR_SUCCESS)
{
DisplayName[0] = 0;
ret = ERROR_SUCCESS;
}
len = sizeof(Publisher) - 1;
ret = RegGetValueA(subkey, NULL, "Publisher", RRF_RT_ANY, NULL, Publisher, &len);
if(ret != ERROR_SUCCESS)
{
Publisher[0] = 0;
ret = ERROR_SUCCESS;
}
// if this is our key, set the version number
if(!strcmp(DisplayName, "RenderDoc") && !strcmp(Publisher, "Baldur Karlsson"))
{
DWORD Version = (RENDERDOC_VERSION_MAJOR << 24) | (RENDERDOC_VERSION_MINOR << 16);
DWORD VersionMajor = RENDERDOC_VERSION_MAJOR;
DWORD VersionMinor = RENDERDOC_VERSION_MINOR;
std::string DisplayVersion = MAJOR_MINOR_VERSION_STRING ".0";
RegSetValueExA(subkey, "Version", 0, REG_DWORD, (const BYTE *)&Version, sizeof(Version));
RegSetValueExA(subkey, "VersionMajor", 0, REG_DWORD, (const BYTE *)&VersionMajor,
sizeof(VersionMajor));
RegSetValueExA(subkey, "VersionMinor", 0, REG_DWORD, (const BYTE *)&VersionMinor,
sizeof(VersionMinor));
RegSetValueExA(subkey, "DisplayVersion", 0, REG_SZ, (const BYTE *)DisplayVersion.c_str(),
(DWORD)DisplayVersion.size() + 1);
done = true;
}
}
if(subkey)
RegCloseKey(subkey);
}
if(key)
RegCloseKey(key);
#endif
}
static std::string ResourceFormatName(const ResourceFormat &fmt)
{
std::string ret;