Add a mostly-complete capture dialog

This commit is contained in:
baldurk
2016-11-09 18:35:48 +01:00
parent 27f1aa71a6
commit 28f5bdcf9d
10 changed files with 1895 additions and 8 deletions
+19
View File
@@ -122,6 +122,25 @@ void RenderManager::CloseThread()
m_Thread = NULL;
}
uint32_t RenderManager::ExecuteAndInject(const QString &exe, const QString &workingDir,
const QString &cmdLine,
const QList<EnvironmentModification> &env,
const QString &logfile, CaptureOptions opts)
{
// if (m_Remote == null)
{
// TODO env
return RENDERDOC_ExecuteAndInject(exe.toUtf8().data(), workingDir.toUtf8().data(),
cmdLine.toUtf8().data(), NULL, logfile.toUtf8().data(), &opts,
false);
}
/*
else
{
}
*/
}
void RenderManager::PushInvoke(RenderManager::InvokeHandle *cmd)
{
if(m_Thread == NULL || !m_Thread->isRunning() || !m_Running)
+60
View File
@@ -29,6 +29,7 @@
#include <QSemaphore>
#include <QString>
#include <QThread>
#include <QVariantMap>
#include <QWaitCondition>
#include <functional>
#include "renderdoc_replay.h"
@@ -40,6 +41,61 @@ class LambdaThread;
#define INVOKE_MEMFN(function) \
m_Ctx->Renderer()->AsyncInvoke([this](IReplayRenderer *r) { function(r); });
struct EnvironmentModification
{
QString variable;
QString value;
EnvironmentModificationType type;
EnvironmentSeparator separator;
QString GetTypeString() const
{
QString ret;
if(type == eEnvMod_Append)
ret = QString("Append, %1").arg("TODO");
else if(type == eEnvMod_Prepend)
ret = QString("Prepend, %1").arg("TODO");
else
ret = "Set";
return ret;
}
QString GetDescription() const
{
QString ret;
if(type == eEnvMod_Append)
ret = QString("Append %1 with %2 using %3").arg(variable).arg(value).arg("TODO");
else if(type == eEnvMod_Prepend)
ret = QString("Prepend %1 with %2 using %3").arg(variable).arg(value).arg("TODO");
else
ret = QString("Set %1 to %2").arg(variable).arg(value);
return ret;
}
QVariantMap toJSON() const
{
QVariantMap ret;
ret["variable"] = variable;
ret["value"] = value;
ret["type"] = "Append"; // TODO
ret["separator"] = "Semi-colon"; // TODO
return ret;
}
void fromJSON(const QVariantMap &data)
{
variable = data["variable"].toString();
value = data["value"].toString();
type = eEnvMod_Append; // TODO
separator = eEnvSep_SemiColon; // TODO
}
};
class RenderManager
{
public:
@@ -58,6 +114,10 @@ public:
void CloseThread();
uint32_t ExecuteAndInject(const QString &exe, const QString &workingDir, const QString &cmdLine,
const QList<EnvironmentModification> &env, const QString &logfile,
CaptureOptions opts);
private:
struct InvokeHandle
{
@@ -0,0 +1,619 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016 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 "CaptureDialog.h"
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include "Code/QRDUtils.h"
#include "FlowLayout.h"
#include "ui_CaptureDialog.h"
#define JSON_ID "rdocCaptureSettings"
#define JSON_VER 1
Q_DECLARE_METATYPE(CaptureSettings);
CaptureSettings::CaptureSettings()
{
Inject = false;
AutoStart = false;
RENDERDOC_GetDefaultCaptureOptions(&Options);
}
QVariantMap CaptureSettings::toJSON() const
{
QVariantMap ret;
ret["AutoStart"] = AutoStart;
ret["Executable"] = Executable;
ret["WorkingDir"] = WorkingDir;
ret["CmdLine"] = CmdLine;
QVariantList env;
for(int i = 0; i < Environment.size(); i++)
env.push_back(Environment[i].toJSON());
ret["Environment"] = env;
QVariantMap opts;
opts["AllowVSync"] = Options.AllowVSync;
opts["AllowFullscreen"] = Options.AllowFullscreen;
opts["APIValidation"] = Options.APIValidation;
opts["CaptureCallstacks"] = Options.CaptureCallstacks;
opts["CaptureCallstacksOnlyDraws"] = Options.CaptureCallstacksOnlyDraws;
opts["DelayForDebugger"] = Options.DelayForDebugger;
opts["VerifyMapWrites"] = Options.VerifyMapWrites;
opts["HookIntoChildren"] = Options.HookIntoChildren;
opts["RefAllResources"] = Options.RefAllResources;
opts["SaveAllInitials"] = Options.SaveAllInitials;
opts["CaptureAllCmdLists"] = Options.CaptureAllCmdLists;
opts["DebugOutputMute"] = Options.DebugOutputMute;
ret["Options"] = opts;
return ret;
}
void CaptureSettings::fromJSON(const QVariantMap &data)
{
AutoStart = data["AutoStart"].toBool();
Executable = data["Executable"].toString();
WorkingDir = data["WorkingDir"].toString();
CmdLine = data["CmdLine"].toString();
QVariantList env = data["Environment"].toList();
for(int i = 0; i < env.size(); i++)
{
EnvironmentModification e;
e.fromJSON(env[i].value<QVariantMap>());
Environment.push_back(e);
}
QVariantMap opts = data["Options"].toMap();
Options.AllowVSync = opts["AllowVSync"].toBool();
Options.AllowFullscreen = opts["AllowFullscreen"].toBool();
Options.APIValidation = opts["APIValidation"].toBool();
Options.CaptureCallstacks = opts["CaptureCallstacks"].toBool();
Options.CaptureCallstacksOnlyDraws = opts["CaptureCallstacksOnlyDraws"].toBool();
Options.DelayForDebugger = opts["DelayForDebugger"].toUInt();
Options.VerifyMapWrites = opts["VerifyMapWrites"].toBool();
Options.HookIntoChildren = opts["HookIntoChildren"].toBool();
Options.RefAllResources = opts["RefAllResources"].toBool();
Options.SaveAllInitials = opts["SaveAllInitials"].toBool();
Options.CaptureAllCmdLists = opts["CaptureAllCmdLists"].toBool();
Options.DebugOutputMute = opts["DebugOutputMute"].toBool();
}
CaptureDialog::CaptureDialog(CaptureContext *ctx, OnCaptureMethod captureCallback,
OnInjectMethod injectCallback, QWidget *parent)
: QFrame(parent), ui(new Ui::CaptureDialog), m_Ctx(ctx)
{
ui->setupUi(this);
// setup FlowLayout for options group
{
QLayout *oldLayout = ui->optionsGroup->layout();
QObjectList options = ui->optionsGroup->children();
options.removeOne((QObject *)oldLayout);
delete oldLayout;
FlowLayout *optionsFlow = new FlowLayout(ui->optionsGroup, -1, 3, 3);
for(QObject *o : options)
optionsFlow->addWidget(qobject_cast<QWidget *>(o));
ui->optionsGroup->setLayout(optionsFlow);
}
ui->envVar->setEnabled(false);
m_ProcessModel = new QStandardItemModel(0, 3, this);
m_ProcessModel->setHeaderData(0, Qt::Horizontal, tr("Name"));
m_ProcessModel->setHeaderData(1, Qt::Horizontal, tr("PID"));
m_ProcessModel->setHeaderData(2, Qt::Horizontal, tr("Window Title"));
QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
proxy->setSourceModel(m_ProcessModel);
// filter on all columns
proxy->setFilterKeyColumn(-1);
// allow updating the underlying model
proxy->setDynamicSortFilter(true);
ui->processList->setModel(proxy);
ui->processList->setAlternatingRowColors(true);
// sort by PID by default
ui->processList->sortByColumn(1, Qt::AscendingOrder);
// TODO
ui->vulkanLayerWarn->setVisible(true);
m_CaptureCallback = captureCallback;
m_InjectCallback = injectCallback;
setSettings(CaptureSettings());
updateGlobalHook();
}
CaptureDialog::~CaptureDialog()
{
delete ui;
}
void CaptureDialog::setInjectMode(bool inject)
{
m_Inject = inject;
if(inject)
{
ui->injectGroup->setVisible(true);
ui->exeGroup->setVisible(false);
ui->topVerticalSpacer->spacerItem()->changeSize(0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum);
ui->verticalLayout->invalidate();
ui->globalGroup->setVisible(false);
fillProcessList();
ui->capture->setText("Inject");
this->setWindowTitle("Inject into Process");
}
else
{
ui->injectGroup->setVisible(false);
ui->exeGroup->setVisible(true);
ui->topVerticalSpacer->spacerItem()->changeSize(0, 0, QSizePolicy::Minimum,
QSizePolicy::Expanding);
ui->verticalLayout->invalidate();
ui->globalGroup->setVisible(m_Ctx->Config.AllowGlobalHook);
ui->capture->setText("Capture");
this->setWindowTitle("Capture Executable");
}
}
void CaptureDialog::on_CaptureCallstacks_toggled(bool checked)
{
if(ui->CaptureCallstacks->isChecked())
{
ui->CaptureCallstacksOnlyDraws->setEnabled(true);
}
else
{
ui->CaptureCallstacksOnlyDraws->setChecked(false);
ui->CaptureCallstacksOnlyDraws->setEnabled(false);
}
}
void CaptureDialog::on_processFilter_textChanged(const QString &filter)
{
QSortFilterProxyModel *model = (QSortFilterProxyModel *)ui->processList->model();
if(model == NULL)
return;
model->setFilterFixedString(filter);
}
void CaptureDialog::on_exePath_textChanged(const QString &exe)
{
QFileInfo f(exe);
QDir dir = f.dir();
bool valid = dir.makeAbsolute();
if(valid && f.isAbsolute())
ui->workDirPath->setPlaceholderText(QDir::toNativeSeparators(dir.absolutePath()));
else if(exe == "")
ui->workDirPath->setPlaceholderText("");
updateGlobalHook();
}
void CaptureDialog::on_vulkanCapture_clicked()
{
// TODO
}
void CaptureDialog::on_processRefesh_clicked()
{
fillProcessList();
}
void CaptureDialog::on_exePathBrowse_clicked()
{
QString initDir = "";
QString file = "";
QFileInfo f(ui->exePath->text());
QDir dir = f.dir();
if(ui->exePath->text() != "" && f.isAbsolute() && dir.exists())
{
initDir = dir.absolutePath();
}
else if(m_Ctx->Config.LastCapturePath != "")
{
initDir = m_Ctx->Config.LastCapturePath;
if(m_Ctx->Config.LastCaptureExe != "")
file = m_Ctx->Config.LastCaptureExe;
}
// if(m_Core.Renderer.Remote == null)
{
QString filename = RDDialog::getOpenFileName(this, tr("Choose executable"), initDir,
"Executable files (*.exe);;All files (*.*)");
if(filename != "")
setExecutableFilename(filename);
}
/*
else
{
VirtualOpenFileDialog remoteBrowser = new VirtualOpenFileDialog(m_Core.Renderer);
remoteBrowser.Opened += new EventHandler<FileOpenedEventArgs>(this.virtualExeBrowser_Opened);
remoteBrowser.ShowDialog(this);
}
*/
}
void CaptureDialog::on_workDirBrowse_clicked()
{
QString initDir = "";
if(QDir(ui->workDirPath->text()).exists())
{
initDir = ui->workDirPath->text();
}
else
{
QDir dir = QFileInfo(ui->exePath->text()).dir();
if(dir.exists())
initDir = dir.absolutePath();
else if(m_Ctx->Config.LastCapturePath != "")
initDir = m_Ctx->Config.LastCapturePath;
}
// if(m_Core.Renderer.Remote == null)
{
QString dir = RDDialog::getExistingDirectory(this, "Choose working directory", initDir);
if(dir != "")
ui->workDirPath->setText(dir);
}
/*
else
{
VirtualOpenFileDialog remoteBrowser = new VirtualOpenFileDialog(m_Core.Renderer);
remoteBrowser.Opened += new
EventHandler<FileOpenedEventArgs>(this.virtualWorkDirBrowser_Opened);
remoteBrowser.DirectoryBrowse = true;
remoteBrowser.ShowDialog(this);
}
*/
}
void CaptureDialog::on_envVarEdit_clicked()
{
// TODO
}
void CaptureDialog::on_toggleGlobal_clicked()
{
if(ui->toggleGlobal->isEnabled())
{
ui->toggleGlobal->setChecked(!ui->toggleGlobal->isChecked());
updateGlobalHook();
}
}
void CaptureDialog::on_saveSettings_clicked()
{
QString filename = RDDialog::getSaveFileName(this, tr("Save Settings As"), QString(),
"Capture settings (*.cap)");
if(filename != "")
{
QDir dirinfo = QFileInfo(filename).dir();
if(dirinfo.exists())
{
saveSettings(filename);
PersistantConfig::AddRecentFile(m_Ctx->Config.RecentCaptureSettings, filename, 10);
}
}
}
void CaptureDialog::on_loadSettings_clicked()
{
QString filename =
RDDialog::getOpenFileName(this, tr("Open Settings"), QString(), "Capture settings (*.cap)");
if(filename != "" && QFileInfo::exists(filename))
{
loadSettings(filename);
PersistantConfig::AddRecentFile(m_Ctx->Config.RecentCaptureSettings, filename, 10);
}
}
void CaptureDialog::on_capture_clicked()
{
triggerCapture();
}
void CaptureDialog::on_close_clicked()
{
this->close();
}
void CaptureDialog::setSettings(CaptureSettings settings)
{
setInjectMode(settings.Inject);
ui->exePath->setText(settings.Executable);
ui->workDirPath->setText(settings.WorkingDir);
ui->cmdline->setText(settings.CmdLine);
setEnvironmentModifications(settings.Environment);
ui->AllowFullscreen->setChecked(settings.Options.AllowFullscreen);
ui->AllowVSync->setChecked(settings.Options.AllowVSync);
ui->HookIntoChildren->setChecked(settings.Options.HookIntoChildren);
ui->CaptureCallstacks->setChecked(settings.Options.CaptureCallstacks);
ui->CaptureCallstacksOnlyDraws->setChecked(settings.Options.CaptureCallstacksOnlyDraws);
ui->APIValidation->setChecked(settings.Options.APIValidation);
ui->RefAllResources->setChecked(settings.Options.RefAllResources);
ui->SaveAllInitials->setChecked(settings.Options.SaveAllInitials);
ui->DelayForDebugger->setValue(settings.Options.DelayForDebugger);
ui->VerifyMapWrites->setChecked(settings.Options.VerifyMapWrites);
ui->AutoStart->setChecked(settings.AutoStart);
if(settings.AutoStart)
{
triggerCapture();
}
}
CaptureSettings CaptureDialog::settings()
{
CaptureSettings ret;
ret.Inject = injectMode();
ret.AutoStart = ui->AutoStart->isChecked();
ret.Executable = ui->exePath->text();
ret.WorkingDir = ui->workDirPath->text();
ret.CmdLine = ui->cmdline->text();
ret.Environment = m_EnvModifications;
ret.Options.AllowFullscreen = ui->AllowFullscreen->isChecked();
ret.Options.AllowVSync = ui->AllowVSync->isChecked();
ret.Options.HookIntoChildren = ui->HookIntoChildren->isChecked();
ret.Options.CaptureCallstacks = ui->CaptureCallstacks->isChecked();
ret.Options.CaptureCallstacksOnlyDraws = ui->CaptureCallstacksOnlyDraws->isChecked();
ret.Options.APIValidation = ui->APIValidation->isChecked();
ret.Options.RefAllResources = ui->RefAllResources->isChecked();
ret.Options.SaveAllInitials = ui->SaveAllInitials->isChecked();
ret.Options.CaptureAllCmdLists = ui->CaptureAllCmdLists->isChecked();
ret.Options.DelayForDebugger = (uint32_t)ui->DelayForDebugger->value();
ret.Options.VerifyMapWrites = ui->VerifyMapWrites->isChecked();
return ret;
}
void CaptureDialog::saveSettings(QString filename)
{
QFile f(filename);
if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
QVariantMap values;
values["settings"] = settings().toJSON();
SaveToJSON(values, f, JSON_ID, JSON_VER);
}
else
{
RDDialog::critical(this, "Error saving config",
tr("Couldn't open path %1 for write.").arg(filename));
}
}
void CaptureDialog::fillProcessList()
{
m_ProcessModel->removeRows(0, m_ProcessModel->rowCount());
// no way of listing processes in Qt, fill with dummy data
m_ProcessModel->insertRows(0, 5);
#define ROW(n, name, pid, title) \
m_ProcessModel->setData(m_ProcessModel->index(n, 0), name); \
m_ProcessModel->setData(m_ProcessModel->index(n, 1), pid); \
m_ProcessModel->setData(m_ProcessModel->index(n, 2), title);
ROW(0, "foo.exe", 123, "Foo Window");
ROW(1, "magic.exe", 456, "Magic Window");
ROW(2, "system", 999, "Scary System process");
ROW(3, "chrome.exe", 4539, "Chrome - renderdoc.org");
ROW(4, "firefox.exe", 8483, "Firefox - renderdoc.org");
}
void CaptureDialog::setExecutableFilename(QString filename)
{
filename = QDir::toNativeSeparators(QFileInfo(filename).absoluteFilePath());
ui->exePath->setText(filename);
m_Ctx->Config.LastCapturePath = QFileInfo(filename).absolutePath();
m_Ctx->Config.LastCaptureExe = QFileInfo(filename).completeBaseName();
}
void CaptureDialog::loadSettings(QString filename)
{
QFile f(filename);
if(f.open(QIODevice::ReadOnly | QIODevice::Text))
{
QVariantMap values;
bool success = LoadFromJSON(values, f, JSON_ID, JSON_VER);
if(success)
{
CaptureSettings settings;
settings.fromJSON(values["settings"].value<QVariantMap>());
setSettings(settings);
}
else
{
RDDialog::critical(this, "Error loading config",
tr("Couldn't interpret settings in %1.").arg(filename));
}
}
else
{
RDDialog::critical(this, "Error loading config", tr("Couldn't open path %1.").arg(filename));
}
}
void CaptureDialog::closeEvent(QCloseEvent *event)
{
if(ui->toggleGlobal->isChecked())
{
ui->toggleGlobal->setChecked(false);
updateGlobalHook();
}
}
void CaptureDialog::updateGlobalHook()
{
ui->globalGroup->setVisible(!injectMode() && m_Ctx->Config.AllowGlobalHook);
if(ui->exePath->text().length() >= 4)
{
ui->toggleGlobal->setEnabled(true);
QString text = tr("Global hooking is risky!\nBe sure you know what you're doing.");
if(ui->toggleGlobal->isChecked())
text += tr("\nEmergency restore @ %TEMP%\\RenderDoc_RestoreGlobalHook.reg");
ui->globalLabel->setText(text);
}
else
{
ui->toggleGlobal->setEnabled(false);
ui->globalLabel->setText(tr("Global hooking requires an executable path, or filename"));
}
}
void CaptureDialog::setEnvironmentModifications(const QList<EnvironmentModification> &modifications)
{
m_EnvModifications = modifications;
QString envModText = "";
for(const EnvironmentModification &mod : modifications)
{
if(envModText != "")
envModText += ", ";
envModText += mod.GetDescription();
}
ui->envVar->setText(envModText);
}
void CaptureDialog::triggerCapture()
{
if(injectMode())
{
QModelIndexList sel = ui->processList->selectionModel()->selectedRows();
if(sel.size() == 1)
{
QModelIndex item = sel[0];
QSortFilterProxyModel *model = (QSortFilterProxyModel *)ui->processList->model();
item = model->mapToSource(item);
QString name = m_ProcessModel->data(m_ProcessModel->index(item.row(), 0)).toString();
uint32_t PID = m_ProcessModel->data(m_ProcessModel->index(item.row(), 1)).toUInt();
// var live = ;
m_InjectCallback(PID, settings().Environment, name, settings().Options);
/*
if(queueFrameCap.Checked && live != null)
live.QueueCapture((int)queuedCapFrame.Value);
*/
}
}
else
{
QString exe = ui->exePath->text();
// for non-remote captures, check the executable locally
// if(m_Core.Renderer.Remote == null)
{
if(!QFileInfo::exists(exe))
{
RDDialog::critical(this, tr("Invalid executable"),
tr("Invalid application executable: %1").arg(exe));
return;
}
}
QString workingDir = "";
// for non-remote captures, check the directory locally
// if(m_Core.Renderer.Remote == null)
{
if(QDir(ui->workDirPath->text()).exists())
workingDir = ui->workDirPath->text();
}
/*
else
{
workingDir = RealWorkDir;
}
*/
QString cmdLine = ui->cmdline->text();
// var live =
m_CaptureCallback(exe, workingDir, cmdLine, settings().Environment, settings().Options);
/*
if(queueFrameCap.Checked && live != null)
live.QueueCapture((int)queuedCapFrame.Value);
*/
}
}
+121
View File
@@ -0,0 +1,121 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016 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 <QFrame>
#include <functional>
#include "Code/CaptureContext.h"
namespace Ui
{
class CaptureDialog;
}
class QStandardItemModel;
struct CaptureSettings
{
CaptureSettings();
CaptureOptions Options;
bool Inject;
bool AutoStart;
QString Executable;
QString WorkingDir;
QString CmdLine;
QList<EnvironmentModification> Environment;
QVariantMap toJSON() const;
void fromJSON(const QVariantMap &data);
};
class CaptureDialog : public QFrame
{
Q_OBJECT
public:
typedef std::function<void(const QString &exe, const QString &workingDir, const QString &cmdLine,
const QList<EnvironmentModification> &env, CaptureOptions opts)>
OnCaptureMethod;
typedef std::function<void(uint32_t PID, const QList<EnvironmentModification> &env,
const QString &name, CaptureOptions opts)>
OnInjectMethod;
explicit CaptureDialog(CaptureContext *ctx, OnCaptureMethod captureCallback,
OnInjectMethod injectCallback, QWidget *parent = 0);
~CaptureDialog();
bool injectMode() { return m_Inject; }
void setInjectMode(bool inject);
void setExecutableFilename(QString filename);
void loadSettings(QString filename);
private slots:
// automatic slots
void on_exePathBrowse_clicked();
void on_exePath_textChanged(const QString &arg1);
void on_workDirBrowse_clicked();
void on_envVarEdit_clicked();
void on_processFilter_textChanged(const QString &arg1);
void on_processRefesh_clicked();
void on_saveSettings_clicked();
void on_loadSettings_clicked();
void on_capture_clicked();
void on_close_clicked();
void on_toggleGlobal_clicked();
void on_vulkanCapture_clicked();
void on_CaptureCallstacks_toggled(bool checked);
private:
void closeEvent(QCloseEvent *event) override;
Ui::CaptureDialog *ui;
CaptureContext *m_Ctx;
QStandardItemModel *m_ProcessModel;
OnCaptureMethod m_CaptureCallback;
OnInjectMethod m_InjectCallback;
void updateGlobalHook();
void setEnvironmentModifications(const QList<EnvironmentModification> &modifications);
void triggerCapture();
void setSettings(CaptureSettings settings);
CaptureSettings settings();
void saveSettings(QString filename);
QList<EnvironmentModification> m_EnvModifications;
bool m_Inject;
void fillProcessList();
};
+926
View File
@@ -0,0 +1,926 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CaptureDialog</class>
<widget class="QFrame" name="CaptureDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>270</width>
<height>939</height>
</rect>
</property>
<property name="windowTitle">
<string>Capture Executable</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="exeGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>130</height>
</size>
</property>
<property name="title">
<string>Program</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>4</number>
</property>
<item row="0" column="2">
<widget class="QLineEdit" name="exePath">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="exePathBrowse">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="workDirLabel">
<property name="text">
<string>Working Directory</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="workDirBrowse">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="cmdLineLabel">
<property name="text">
<string>Command-line Arguments</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="envVarLabel">
<property name="text">
<string>Environment Variables</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QToolButton" name="envVarEdit">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="exePathLabel">
<property name="text">
<string>Executable Path</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="workDirPath">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QLineEdit" name="cmdline">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="envVar">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="injectGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>260</height>
</size>
</property>
<property name="title">
<string>Process</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<widget class="QPushButton" name="processRefesh">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="processWarning">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</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>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="text">
<string>NOTE: Injecting only works when the process has not used the target API</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="processFilter">
<property name="placeholderText">
<string>Filter process list by PID or name</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTreeView" name="processList">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QToolButton" name="vulkanLayerWarn">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>36</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>220</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>Warning: Vulkan capture is not configured.
Click here to set up Vulkan capture.</string>
</property>
<property name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/Resources/information.png</normaloff>:/Resources/information.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::DelayedPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
<property name="arrowType">
<enum>Qt::NoArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="optionsGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Capture Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="AllowFullscreen">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Allow Fullscreen</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AllowVSync">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Allow VSync</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="DebuggerDelayFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>4</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="QDoubleSpinBox" name="DelayForDebugger">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string comment="seconds"> secs</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="DebuggerDelayLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Debugger Delay</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="CaptureCallstacks">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Collect Callstacks</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="CaptureCallstacksOnlyDraws">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Only Drawcall stacks</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="APIValidation">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Enable API Validation</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="HookIntoChildren">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Hook into Children</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="SaveAllInitials">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Save all Initials</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="RefAllResources">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Ref all Resources</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="CaptureAllCmdLists">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Capture all Cmd Lists</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="VerifyMapWrites">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Verify Map() Writes</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AutoStart">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Auto Start</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="actionGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Actions</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QCheckBox" name="queueCaptureLabel">
<property name="text">
<string>Queue Capture</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="queuedFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="prefix">
<string comment="Frame number" extracomment="To Capture">Frame </string>
</property>
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>0</number>
</property>
</widget>
</item>
<item>
<spacer name="ActionsSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>596</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="globalGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Global Process Hook</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="globalLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</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>
</disabled>
</palette>
</property>
<property name="text">
<string>Text Set by Code</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toggleGlobal">
<property name="text">
<string>Enable Global Hook</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="globalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>587</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="buttonsFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="saveSettings">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loadSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<spacer name="buttonsSpace">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>556</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="capture">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Capture</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="close">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="topVerticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../../resources.qrc"/>
</resources>
<connections/>
</ui>
+115 -7
View File
@@ -30,6 +30,7 @@
#include "Code/CaptureContext.h"
#include "Code/QRDUtils.h"
#include "Windows/Dialogs/AboutDialog.h"
#include "Windows/Dialogs/CaptureDialog.h"
#include "EventBrowser.h"
#include "TextureViewer.h"
#include "ui_MainWindow.h"
@@ -110,6 +111,11 @@ MainWindow::MainWindow(CaptureContext *ctx) : QMainWindow(NULL), ui(new Ui::Main
eventBrowser->setObjectName("eventBrowser");
return eventBrowser;
}
else if(objectName == "capDialog")
{
CaptureDialog *capDialog = this->createCaptureDialog();
return capDialog;
}
return NULL;
});
@@ -131,6 +137,12 @@ MainWindow::MainWindow(CaptureContext *ctx) : QMainWindow(NULL), ui(new Ui::Main
textureViewer,
ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
ui->toolWindowManager->areaOf(eventBrowser), 0.75f));
CaptureDialog *capDialog = createCaptureDialog();
ui->toolWindowManager->addToolWindow(
capDialog, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
ui->toolWindowManager->areaOf(textureViewer)));
}
}
@@ -173,17 +185,17 @@ void MainWindow::LoadFromFilename(const QString &filename)
QFileInfo path(filename);
QString ext = path.suffix().toLower();
if(ext == ".rdc")
if(ext == "rdc")
{
LoadLogfile(filename, false, true);
}
else if(ext == ".cap")
else if(ext == "cap")
{
// OpenCaptureConfigFile(filename, false);
OpenCaptureConfigFile(filename, false);
}
else if(ext == ".exe")
else if(ext == "exe")
{
// OpenCaptureConfigFile(filename, true);
OpenCaptureConfigFile(filename, true);
}
else
{
@@ -192,6 +204,59 @@ void MainWindow::LoadFromFilename(const QString &filename)
}
}
void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
const QString &cmdLine, const QList<EnvironmentModification> &env,
CaptureOptions opts)
{
if(!PromptCloseLog())
return;
QString logfile = m_Ctx->TempLogFilename(QFileInfo(exe).baseName());
uint32_t ret = m_Ctx->Renderer()->ExecuteAndInject(exe, workingDir, cmdLine, env, logfile, opts);
if(ret == 0)
{
RDDialog::critical(
this, tr("Error kicking capture"),
tr("Error launching %1 for capture.\n\nCheck diagnostic log in Help menu for more details.")
.arg(exe));
return;
}
/*
var live = new LiveCapture(m_Core, m_Core.Renderer.Remote == null ? "" :
m_Core.Renderer.Remote.Hostname, ret, this);
ShowLiveCapture(live);
return live;*/
}
void MainWindow::OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env,
const QString &name, CaptureOptions opts)
{
if(!PromptCloseLog())
return;
QString logfile = m_Ctx->TempLogFilename(name);
// TODO - env
uint32_t ret = RENDERDOC_InjectIntoProcess(PID, NULL, logfile.toUtf8().data(), &opts, false);
if(ret == 0)
{
RDDialog::critical(this, tr("Error kicking capture"),
tr("Error injecting into process %1 for capture.\n\nCheck diagnostic log in "
"Help menu for more details.")
.arg(PID));
return;
}
/*
var live = new LiveCapture(m_Core, "", ret, this);
ShowLiveCapture(live);
return live;*/
}
void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local)
{
if(PromptCloseLog())
@@ -352,13 +417,25 @@ void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local
if(!remoteReplay)
{
m_Ctx->Config.LastLogPath = QFileInfo(filename).dir().absolutePath();
m_Ctx->Config.LastLogPath = QFileInfo(filename).absolutePath();
}
statusText->setText(tr("Loading ") + origFilename + "...");
}
}
void MainWindow::OpenCaptureConfigFile(const QString &filename, bool exe)
{
CaptureDialog *capDialog = createCaptureDialog();
if(exe)
capDialog->setExecutableFilename(filename);
else
capDialog->loadSettings(filename);
ui->toolWindowManager->addToolWindow(capDialog, ToolWindowManager::EmptySpace);
}
QString MainWindow::GetSavePath()
{
QString dir;
@@ -490,6 +567,19 @@ void MainWindow::CloseLogfile()
ui->action_Save_Log->setEnabled(false);
}
CaptureDialog *MainWindow::createCaptureDialog()
{
CaptureDialog *ret = new CaptureDialog(
m_Ctx,
[this](const QString &exe, const QString &workingDir, const QString &cmdLine,
const QList<EnvironmentModification> &env,
CaptureOptions opts) { this->OnCaptureTrigger(exe, workingDir, cmdLine, env, opts); },
[this](uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
CaptureOptions opts) { this->OnInjectTrigger(PID, env, name, opts); });
ret->setObjectName("capDialog");
return ret;
}
void MainWindow::SetTitle(const QString &filename)
{
QString prefix = "";
@@ -595,7 +685,7 @@ void MainWindow::recentCapture(const QString &filename)
{
if(QFileInfo::exists(filename))
{
// OpenCaptureConfigFile(filename, false);
OpenCaptureConfigFile(filename, false);
}
else
{
@@ -715,6 +805,24 @@ void MainWindow::on_action_Texture_Viewer_triggered()
ui->toolWindowManager->addToolWindow(textureViewer, ToolWindowManager::EmptySpace);
}
void MainWindow::on_action_Capture_Log_triggered()
{
CaptureDialog *capDialog = createCaptureDialog();
ui->toolWindowManager->addToolWindow(capDialog, ToolWindowManager::EmptySpace);
capDialog->setInjectMode(false);
}
void MainWindow::on_action_Inject_into_Process_triggered()
{
CaptureDialog *capDialog = createCaptureDialog();
ui->toolWindowManager->addToolWindow(capDialog, ToolWindowManager::EmptySpace);
capDialog->setInjectMode(true);
}
void MainWindow::saveLayout_triggered()
{
LoadSaveLayout(qobject_cast<QAction *>(QObject::sender()), true);
+11
View File
@@ -35,6 +35,7 @@ class MainWindow;
class QLabel;
class QProgressBar;
class CaptureDialog;
class MainWindow : public QMainWindow, public ILogViewerForm
{
@@ -53,6 +54,11 @@ public:
bool ownTemporaryLog() { return m_OwnTempLog; }
void LoadFromFilename(const QString &filename);
void OnCaptureTrigger(const QString &exe, const QString &workingDir, const QString &cmdLine,
const QList<EnvironmentModification> &env, CaptureOptions opts);
void OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
CaptureOptions opts);
private slots:
// automatic slots
void on_action_Exit_triggered();
@@ -62,6 +68,8 @@ private slots:
void on_action_Mesh_Output_triggered();
void on_action_Event_Viewer_triggered();
void on_action_Texture_Viewer_triggered();
void on_action_Capture_Log_triggered();
void on_action_Inject_into_Process_triggered();
// manual slots
void saveLayout_triggered();
@@ -85,6 +93,8 @@ private:
QString m_LastSaveCapturePath = "";
CaptureDialog *createCaptureDialog();
void SetTitle(const QString &filename);
void SetTitle();
@@ -97,6 +107,7 @@ private:
bool PromptCloseLog();
bool PromptSaveLog();
void LoadLogfile(const QString &filename, bool temporary, bool local);
void OpenCaptureConfigFile(const QString &filename, bool exe);
QString GetSavePath();
void CloseLogfile();
+4 -1
View File
@@ -96,6 +96,7 @@ SOURCES += 3rdparty/toolwindowmanager/ToolWindowManager.cpp \
Widgets/TextureGoto.cpp \
Widgets/RangeHistogram.cpp \
Windows/Dialogs/TextureSaveDialog.cpp \
Windows/Dialogs/CaptureDialog.cpp \
Code/QRDUtils.cpp
HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
@@ -120,6 +121,7 @@ HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
Widgets/TextureGoto.h \
Widgets/RangeHistogram.h \
Windows/Dialogs/TextureSaveDialog.h \
Windows/Dialogs/CaptureDialog.h \
Code/QRDUtils.h
FORMS += Windows/Dialogs/AboutDialog.ui \
@@ -128,7 +130,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/TextureViewer.ui \
Widgets/ResourcePreview.ui \
Widgets/ThumbnailStrip.ui \
Windows/Dialogs/TextureSaveDialog.ui
Windows/Dialogs/TextureSaveDialog.ui \
Windows/Dialogs/CaptureDialog.ui
RESOURCES += \
resources.qrc
+5
View File
@@ -281,6 +281,7 @@
<ClCompile Include="Code\QRDUtils.cpp" />
<ClCompile Include="generated\moc_AboutDialog.cpp" />
<ClCompile Include="generated\moc_CaptureContext.cpp" />
<ClCompile Include="generated\moc_CaptureDialog.cpp" />
<ClCompile Include="generated\moc_CustomPaintWidget.cpp" />
<ClCompile Include="generated\moc_EventBrowser.cpp" />
<ClCompile Include="generated\moc_QRDUtils.cpp" />
@@ -309,6 +310,7 @@
<ClCompile Include="Code\CaptureContext.cpp" />
<ClCompile Include="Widgets\CustomPaintWidget.cpp" />
<ClCompile Include="Windows\Dialogs\AboutDialog.cpp" />
<ClCompile Include="Windows\Dialogs\CaptureDialog.cpp" />
<ClCompile Include="Windows\Dialogs\TextureSaveDialog.cpp" />
<ClCompile Include="Windows\EventBrowser.cpp" />
<ClCompile Include="3rdparty\flowlayout\FlowLayout.cpp">
@@ -334,6 +336,7 @@
<ClInclude Include="Code\PersistantConfig.h" />
<ClInclude Include="Code\QRDUtils.h" />
<ClInclude Include="generated\ui_AboutDialog.h" />
<ClInclude Include="generated\ui_CaptureDialog.h" />
<ClInclude Include="generated\ui_EventBrowser.h" />
<ClInclude Include="generated\ui_MainWindow.h" />
<ClInclude Include="generated\ui_ResourcePreview.h" />
@@ -350,6 +353,7 @@
<ClInclude Include="Code\CaptureContext.h" />
<ClInclude Include="Widgets\CustomPaintWidget.h" />
<ClInclude Include="Windows\Dialogs\AboutDialog.h" />
<ClInclude Include="Windows\Dialogs\CaptureDialog.h" />
<ClInclude Include="Windows\Dialogs\TextureSaveDialog.h" />
<ClInclude Include="Windows\EventBrowser.h" />
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h" />
@@ -365,6 +369,7 @@
<None Include="Widgets\ResourcePreview.ui" />
<None Include="Widgets\ThumbnailStrip.ui" />
<None Include="Windows\Dialogs\AboutDialog.ui" />
<None Include="Windows\Dialogs\CaptureDialog.ui" />
<None Include="Windows\Dialogs\TextureSaveDialog.ui" />
<None Include="Windows\EventBrowser.ui" />
<None Include="Windows\MainWindow.ui" />
@@ -169,6 +169,12 @@
<ClCompile Include="generated\moc_TextureSaveDialog.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="generated\moc_CaptureDialog.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
<ClCompile Include="Windows\Dialogs\CaptureDialog.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
<ClCompile Include="Code\QRDUtils.cpp">
<Filter>Code</Filter>
</ClCompile>
@@ -252,6 +258,12 @@
<ClInclude Include="generated\ui_TextureSaveDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="generated\ui_CaptureDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="Windows\Dialogs\CaptureDialog.h">
<Filter>Windows\Dialogs</Filter>
</ClInclude>
<ClInclude Include="Code\QRDUtils.h">
<Filter>Code</Filter>
</ClInclude>
@@ -459,6 +471,9 @@
<None Include="Windows\Dialogs\TextureSaveDialog.ui">
<Filter>Windows\Dialogs</Filter>
</None>
<None Include="Windows\Dialogs\CaptureDialog.ui">
<Filter>Windows\Dialogs</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="generated\ui_AboutDialog.h">