1
0
Fork 0
forked from suyu/suyu
suyu/src/citra_qt/main.cpp
Daniel Lundqvist ba4ca041f4 Allow focus only when in popout mode
Only allow manually setting focus to the rendering widget when in Single Window mode. Apply this behavior to when changing the mode while an app is running.
2014-12-26 19:42:27 +01:00

296 lines
9.8 KiB
C++

#include <thread>
#include <QtGui>
#include <QDesktopWidget>
#include <QFileDialog>
#include "qhexedit.h"
#include "main.hxx"
#include "common/common.h"
#include "common/logging/text_formatter.h"
#include "common/logging/log.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/platform.h"
#include "common/scope_exit.h"
#if EMU_PLATFORM == PLATFORM_LINUX
#include <unistd.h>
#endif
#include "bootmanager.hxx"
#include "hotkeys.hxx"
//debugger
#include "debugger/disassembler.hxx"
#include "debugger/registers.hxx"
#include "debugger/callstack.hxx"
#include "debugger/ramview.hxx"
#include "debugger/graphics.hxx"
#include "debugger/graphics_breakpoints.hxx"
#include "debugger/graphics_cmdlists.hxx"
#include "debugger/graphics_framebuffer.hxx"
#include "core/settings.h"
#include "core/system.h"
#include "core/core.h"
#include "core/loader/loader.h"
#include "core/arm/disassembler/load_symbol_map.h"
#include "citra_qt/config.h"
#include "version.h"
GMainWindow::GMainWindow()
{
Pica::g_debug_context = Pica::DebugContext::Construct();
Config config;
ui.setupUi(this);
statusBar()->hide();
render_window = new GRenderWindow;
render_window->hide();
disasmWidget = new DisassemblerWidget(this, render_window->GetEmuThread());
addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
disasmWidget->hide();
registersWidget = new RegistersWidget(this);
addDockWidget(Qt::RightDockWidgetArea, registersWidget);
registersWidget->hide();
callstackWidget = new CallstackWidget(this);
addDockWidget(Qt::RightDockWidgetArea, callstackWidget);
callstackWidget->hide();
graphicsWidget = new GPUCommandStreamWidget(this);
addDockWidget(Qt::RightDockWidgetArea, graphicsWidget);
graphicsWidget ->hide();
graphicsCommandsWidget = new GPUCommandListWidget(this);
addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget);
graphicsCommandsWidget->hide();
auto graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
graphicsBreakpointsWidget->hide();
auto graphicsFramebufferWidget = new GraphicsFramebufferWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget);
graphicsFramebufferWidget->hide();
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
debug_menu->addAction(disasmWidget->toggleViewAction());
debug_menu->addAction(registersWidget->toggleViewAction());
debug_menu->addAction(callstackWidget->toggleViewAction());
debug_menu->addAction(graphicsWidget->toggleViewAction());
debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
// Set default UI state
// geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
QDesktopWidget* desktop = ((QApplication*)QApplication::instance())->desktop();
QRect screenRect = desktop->screenGeometry(this);
int x, y, w, h;
w = screenRect.width() * 2 / 3;
h = screenRect.height() / 2;
x = (screenRect.x() + screenRect.width()) / 2 - w / 2;
y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100;
setGeometry(x, y, w, h);
// Restore UI state
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra");
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("state").toByteArray());
render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray());
ui.action_Popout_Window_Mode->setChecked(settings.value("popoutWindowMode", true).toBool());
ToggleWindowMode();
// Setup connections
connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()));
connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap()));
connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame()));
connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame()));
connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame()));
connect(ui.action_Popout_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
// BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), disasmWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection);
connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), registersWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection);
connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), callstackWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection);
// Setup hotkeys
RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
RegisterHotkey("Main Window", "Start Emulation");
LoadHotkeys(settings);
connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile()));
connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame()));
std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
setWindowTitle(window_title.c_str());
show();
QStringList args = QApplication::arguments();
if (args.length() >= 2) {
BootGame(args[1].toStdString());
}
}
GMainWindow::~GMainWindow()
{
// will get automatically deleted otherwise
if (render_window->parent() == nullptr)
delete render_window;
Pica::g_debug_context.reset();
}
void GMainWindow::BootGame(std::string filename)
{
LOG_INFO(Frontend, "Citra starting...\n");
System::Init(render_window);
// Load a game or die...
if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {
LOG_CRITICAL(Frontend, "Failed to load ROM!");
}
disasmWidget->Init();
registersWidget->OnCPUStepped();
callstackWidget->OnCPUStepped();
render_window->GetEmuThread().SetFilename(filename);
render_window->GetEmuThread().start();
render_window->show();
// Allow manually setting focus to the render widget if not using popout mode.
if (!ui.action_Popout_Window_Mode->isChecked()) {
render_window->setFocusPolicy(Qt::ClickFocus);
render_window->setFocus();
}
OnStartGame();
}
void GMainWindow::OnMenuLoadFile()
{
QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
if (filename.size())
BootGame(filename.toLatin1().data());
}
void GMainWindow::OnMenuLoadSymbolMap() {
QString filename = QFileDialog::getOpenFileName(this, tr("Load symbol map"), QString(), tr("Symbol map (*)"));
if (filename.size())
LoadSymbolMap(filename.toLatin1().data());
}
void GMainWindow::OnStartGame()
{
render_window->GetEmuThread().SetCpuRunning(true);
ui.action_Start->setEnabled(false);
ui.action_Pause->setEnabled(true);
ui.action_Stop->setEnabled(true);
}
void GMainWindow::OnPauseGame()
{
render_window->GetEmuThread().SetCpuRunning(false);
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(true);
}
void GMainWindow::OnStopGame()
{
render_window->GetEmuThread().SetCpuRunning(false);
// TODO: Shutdown core
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(false);
}
void GMainWindow::OnOpenHotkeysDialog()
{
GHotkeysDialog dialog(this);
dialog.exec();
}
void GMainWindow::ToggleWindowMode()
{
bool enable = ui.action_Popout_Window_Mode->isChecked();
if (enable && render_window->parent() != nullptr)
{
ui.horizontalLayout->removeWidget(render_window);
render_window->setParent(nullptr);
render_window->setVisible(true);
render_window->RestoreGeometry();
render_window->setFocusPolicy(Qt::NoFocus);
}
else if (!enable && render_window->parent() == nullptr)
{
render_window->BackupGeometry();
ui.horizontalLayout->addWidget(render_window);
render_window->setVisible(true);
render_window->setFocusPolicy(Qt::ClickFocus);
render_window->setFocus();
}
}
void GMainWindow::OnConfigure()
{
//GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this);
}
void GMainWindow::closeEvent(QCloseEvent* event)
{
// Save window layout
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra");
settings.setValue("geometry", saveGeometry());
settings.setValue("state", saveState());
settings.setValue("geometryRenderWindow", render_window->saveGeometry());
settings.setValue("popoutWindowMode", ui.action_Popout_Window_Mode->isChecked());
settings.setValue("firstStart", false);
SaveHotkeys(settings);
render_window->close();
QWidget::closeEvent(event);
}
#ifdef main
#undef main
#endif
int __cdecl main(int argc, char* argv[])
{
std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
Log::Filter log_filter(Log::Level::Info);
std::thread logging_thread(Log::TextLoggingLoop, logger, &log_filter);
SCOPE_EXIT({
logger->Close();
logging_thread.join();
});
QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication app(argc, argv);
GMainWindow main_window;
// After settings have been loaded by GMainWindow, apply the filter
log_filter.ParseFilterString(Settings::values.log_filter);
main_window.show();
return app.exec();
}