early-access version 2859
This commit is contained in:
@@ -41,6 +41,9 @@ add_executable(yuzu
|
||||
configuration/configure_audio.cpp
|
||||
configuration/configure_audio.h
|
||||
configuration/configure_audio.ui
|
||||
configuration/configure_camera.cpp
|
||||
configuration/configure_camera.h
|
||||
configuration/configure_camera.ui
|
||||
configuration/configure_cpu.cpp
|
||||
configuration/configure_cpu.h
|
||||
configuration/configure_cpu.ui
|
||||
@@ -254,7 +257,7 @@ endif()
|
||||
create_target_directory_groups(yuzu)
|
||||
|
||||
target_link_libraries(yuzu PRIVATE common core input_common video_core)
|
||||
target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets)
|
||||
target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets Qt::Multimedia)
|
||||
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
|
||||
@@ -213,9 +213,9 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
|
||||
ui->button_ok_num,
|
||||
},
|
||||
{
|
||||
nullptr,
|
||||
ui->button_left_optional_num,
|
||||
ui->button_0_num,
|
||||
nullptr,
|
||||
ui->button_right_optional_num,
|
||||
ui->button_ok_num,
|
||||
},
|
||||
}};
|
||||
@@ -330,7 +330,9 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
|
||||
ui->button_7_num,
|
||||
ui->button_8_num,
|
||||
ui->button_9_num,
|
||||
ui->button_left_optional_num,
|
||||
ui->button_0_num,
|
||||
ui->button_right_optional_num,
|
||||
};
|
||||
|
||||
SetupMouseHover();
|
||||
@@ -342,6 +344,9 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
|
||||
ui->label_header->setText(QString::fromStdU16String(initialize_parameters.header_text));
|
||||
ui->label_sub->setText(QString::fromStdU16String(initialize_parameters.sub_text));
|
||||
|
||||
ui->button_left_optional_num->setText(QChar{initialize_parameters.left_optional_symbol_key});
|
||||
ui->button_right_optional_num->setText(QChar{initialize_parameters.right_optional_symbol_key});
|
||||
|
||||
current_text = initialize_parameters.initial_text;
|
||||
cursor_position = initialize_parameters.initial_cursor_position;
|
||||
|
||||
@@ -932,6 +937,15 @@ void QtSoftwareKeyboardDialog::DisableKeyboardButtons() {
|
||||
button->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto enable_left_optional = initialize_parameters.left_optional_symbol_key != '\0';
|
||||
const auto enable_right_optional = initialize_parameters.right_optional_symbol_key != '\0';
|
||||
|
||||
ui->button_left_optional_num->setEnabled(enable_left_optional);
|
||||
ui->button_left_optional_num->setVisible(enable_left_optional);
|
||||
|
||||
ui->button_right_optional_num->setEnabled(enable_right_optional);
|
||||
ui->button_right_optional_num->setVisible(enable_right_optional);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1019,7 +1033,10 @@ bool QtSoftwareKeyboardDialog::ValidateInputText(const QString& input_text) {
|
||||
}
|
||||
|
||||
if (bottom_osk_index == BottomOSKIndex::NumberPad &&
|
||||
std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return !c.isDigit(); })) {
|
||||
std::any_of(input_text.begin(), input_text.end(), [this](QChar c) {
|
||||
return !c.isDigit() && c != QChar{initialize_parameters.left_optional_symbol_key} &&
|
||||
c != QChar{initialize_parameters.right_optional_symbol_key};
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1384,6 +1401,10 @@ void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) {
|
||||
}
|
||||
};
|
||||
|
||||
// Store the initial row and column.
|
||||
const auto initial_row = row;
|
||||
const auto initial_column = column;
|
||||
|
||||
switch (bottom_osk_index) {
|
||||
case BottomOSKIndex::LowerCase:
|
||||
case BottomOSKIndex::UpperCase: {
|
||||
@@ -1394,6 +1415,11 @@ void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) {
|
||||
auto* curr_button = keyboard_buttons[index][row][column];
|
||||
|
||||
while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
|
||||
// If we returned back to where we started from, break the loop.
|
||||
if (row == initial_row && column == initial_column) {
|
||||
break;
|
||||
}
|
||||
|
||||
move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL);
|
||||
curr_button = keyboard_buttons[index][row][column];
|
||||
}
|
||||
@@ -1408,6 +1434,11 @@ void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) {
|
||||
auto* curr_button = numberpad_buttons[row][column];
|
||||
|
||||
while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) {
|
||||
// If we returned back to where we started from, break the loop.
|
||||
if (row == initial_row && column == initial_column) {
|
||||
break;
|
||||
}
|
||||
|
||||
move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD);
|
||||
curr_button = numberpad_buttons[row][column];
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ private:
|
||||
std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
|
||||
|
||||
// Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
|
||||
std::array<QPushButton*, 110> all_buttons;
|
||||
std::array<QPushButton*, 112> all_buttons;
|
||||
|
||||
std::size_t row{0};
|
||||
std::size_t column{0};
|
||||
|
||||
@@ -3298,6 +3298,24 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="button_left_optional_num">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>28</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QPushButton" name="button_0_num">
|
||||
<property name="sizePolicy">
|
||||
@@ -3316,6 +3334,24 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QPushButton" name="button_right_optional_num">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>28</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QPushButton" name="button_3_num">
|
||||
<property name="sizePolicy">
|
||||
@@ -3494,7 +3530,9 @@ p, li { white-space: pre-wrap; }
|
||||
<tabstop>button_7_num</tabstop>
|
||||
<tabstop>button_8_num</tabstop>
|
||||
<tabstop>button_9_num</tabstop>
|
||||
<tabstop>button_left_optional_num</tabstop>
|
||||
<tabstop>button_0_num</tabstop>
|
||||
<tabstop>button_right_optional_num</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../dist/icons/overlay/overlay.qrc"/>
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCameraImageCapture>
|
||||
#include <QCameraInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
@@ -31,6 +33,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "input_common/drivers/camera.h"
|
||||
#include "input_common/drivers/keyboard.h"
|
||||
#include "input_common/drivers/mouse.h"
|
||||
#include "input_common/drivers/tas_input.h"
|
||||
@@ -801,6 +804,86 @@ void GRenderWindow::TouchEndEvent() {
|
||||
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
|
||||
}
|
||||
|
||||
void GRenderWindow::InitializeCamera() {
|
||||
constexpr auto camera_update_ms = std::chrono::milliseconds{50}; // (50ms, 20Hz)
|
||||
if (!Settings::values.enable_ir_sensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool camera_found = false;
|
||||
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
|
||||
for (const QCameraInfo& cameraInfo : cameras) {
|
||||
if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() ||
|
||||
Settings::values.ir_sensor_device.GetValue() == "Auto") {
|
||||
camera = std::make_unique<QCamera>(cameraInfo);
|
||||
camera_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!camera_found) {
|
||||
return;
|
||||
}
|
||||
|
||||
camera_capture = std::make_unique<QCameraImageCapture>(camera.get());
|
||||
connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this,
|
||||
&GRenderWindow::OnCameraCapture);
|
||||
camera->unload();
|
||||
camera->setCaptureMode(QCamera::CaptureViewfinder);
|
||||
camera->load();
|
||||
camera->start();
|
||||
|
||||
pending_camera_snapshots = 0;
|
||||
is_virtual_camera = false;
|
||||
|
||||
camera_timer = std::make_unique<QTimer>();
|
||||
connect(camera_timer.get(), &QTimer::timeout, [this] { RequestCameraCapture(); });
|
||||
// This timer should be dependent of camera resolution 5ms for every 100 pixels
|
||||
camera_timer->start(camera_update_ms);
|
||||
}
|
||||
|
||||
void GRenderWindow::FinalizeCamera() {
|
||||
if (camera_timer) {
|
||||
camera_timer->stop();
|
||||
}
|
||||
if (camera) {
|
||||
camera->unload();
|
||||
}
|
||||
}
|
||||
|
||||
void GRenderWindow::RequestCameraCapture() {
|
||||
if (!Settings::values.enable_ir_sensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the camera doesn't capture, test for virtual cameras
|
||||
if (pending_camera_snapshots > 5) {
|
||||
is_virtual_camera = true;
|
||||
}
|
||||
// Virtual cameras like obs need to reset the camera every capture
|
||||
if (is_virtual_camera) {
|
||||
camera->stop();
|
||||
camera->start();
|
||||
}
|
||||
|
||||
pending_camera_snapshots++;
|
||||
camera_capture->capture();
|
||||
}
|
||||
|
||||
void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) {
|
||||
constexpr std::size_t camera_width = 320;
|
||||
constexpr std::size_t camera_height = 240;
|
||||
const auto converted =
|
||||
img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio,
|
||||
Qt::TransformationMode::SmoothTransformation)
|
||||
.mirrored(false, true);
|
||||
std::vector<u32> camera_data{};
|
||||
camera_data.resize(camera_width * camera_height);
|
||||
std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32));
|
||||
input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data);
|
||||
pending_camera_snapshots = 0;
|
||||
}
|
||||
|
||||
bool GRenderWindow::event(QEvent* event) {
|
||||
if (event->type() == QEvent::TouchBegin) {
|
||||
TouchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
class GRenderWindow;
|
||||
class GMainWindow;
|
||||
class QCamera;
|
||||
class QCameraImageCapture;
|
||||
class QKeyEvent;
|
||||
|
||||
namespace Core {
|
||||
@@ -164,6 +166,9 @@ public:
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
void InitializeCamera();
|
||||
void FinalizeCamera();
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
void focusOutEvent(QFocusEvent* event) override;
|
||||
@@ -207,6 +212,9 @@ private:
|
||||
void TouchUpdateEvent(const QTouchEvent* event);
|
||||
void TouchEndEvent();
|
||||
|
||||
void RequestCameraCapture();
|
||||
void OnCameraCapture(int requestId, const QImage& img);
|
||||
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||
|
||||
bool InitializeOpenGL();
|
||||
@@ -232,6 +240,12 @@ private:
|
||||
bool first_frame = false;
|
||||
InputCommon::TasInput::TasState last_tas_state;
|
||||
|
||||
bool is_virtual_camera;
|
||||
int pending_camera_snapshots;
|
||||
std::unique_ptr<QCamera> camera;
|
||||
std::unique_ptr<QCameraImageCapture> camera_capture;
|
||||
std::unique_ptr<QTimer> camera_timer;
|
||||
|
||||
Core::System& system;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -368,6 +368,11 @@ void Config::ReadHidbusValues() {
|
||||
}
|
||||
}
|
||||
|
||||
void Config::ReadIrCameraValues() {
|
||||
ReadBasicSetting(Settings::values.enable_ir_sensor);
|
||||
ReadBasicSetting(Settings::values.ir_sensor_device);
|
||||
}
|
||||
|
||||
void Config::ReadAudioValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Audio"));
|
||||
|
||||
@@ -393,6 +398,7 @@ void Config::ReadControlValues() {
|
||||
ReadTouchscreenValues();
|
||||
ReadMotionTouchValues();
|
||||
ReadHidbusValues();
|
||||
ReadIrCameraValues();
|
||||
|
||||
#ifdef _WIN32
|
||||
ReadBasicSetting(Settings::values.enable_raw_input);
|
||||
@@ -998,6 +1004,11 @@ void Config::SaveHidbusValues() {
|
||||
QString::fromStdString(default_param));
|
||||
}
|
||||
|
||||
void Config::SaveIrCameraValues() {
|
||||
WriteBasicSetting(Settings::values.enable_ir_sensor);
|
||||
WriteBasicSetting(Settings::values.ir_sensor_device);
|
||||
}
|
||||
|
||||
void Config::SaveValues() {
|
||||
if (global) {
|
||||
SaveControlValues();
|
||||
@@ -1040,6 +1051,7 @@ void Config::SaveControlValues() {
|
||||
SaveTouchscreenValues();
|
||||
SaveMotionTouchValues();
|
||||
SaveHidbusValues();
|
||||
SaveIrCameraValues();
|
||||
|
||||
WriteGlobalSetting(Settings::values.use_docked_mode);
|
||||
WriteGlobalSetting(Settings::values.vibration_enabled);
|
||||
|
||||
@@ -68,6 +68,7 @@ private:
|
||||
void ReadTouchscreenValues();
|
||||
void ReadMotionTouchValues();
|
||||
void ReadHidbusValues();
|
||||
void ReadIrCameraValues();
|
||||
|
||||
// Read functions bases off the respective config section names.
|
||||
void ReadAudioValues();
|
||||
@@ -96,6 +97,7 @@ private:
|
||||
void SaveTouchscreenValues();
|
||||
void SaveMotionTouchValues();
|
||||
void SaveHidbusValues();
|
||||
void SaveIrCameraValues();
|
||||
|
||||
// Save functions based off the respective config section names.
|
||||
void SaveAudioValues();
|
||||
|
||||
@@ -62,12 +62,23 @@ void ConfigureCamera::PreviewCamera() {
|
||||
camera->unload();
|
||||
camera->setCaptureMode(QCamera::CaptureViewfinder);
|
||||
camera->load();
|
||||
camera->start();
|
||||
|
||||
pending_snapshots = 0;
|
||||
is_virtual_camera = false;
|
||||
|
||||
camera_timer = std::make_unique<QTimer>();
|
||||
connect(camera_timer.get(), &QTimer::timeout, [this] {
|
||||
camera->stop();
|
||||
camera->start();
|
||||
|
||||
// If the camera doesn't capture, test for virtual cameras
|
||||
if (pending_snapshots > 5) {
|
||||
is_virtual_camera = true;
|
||||
}
|
||||
// Virtual cameras like obs need to reset the camera every capture
|
||||
if (is_virtual_camera) {
|
||||
camera->stop();
|
||||
camera->start();
|
||||
}
|
||||
pending_snapshots++;
|
||||
camera_capture->capture();
|
||||
});
|
||||
|
||||
@@ -79,6 +90,7 @@ void ConfigureCamera::DisplayCapturedFrame(int requestId, const QImage& img) {
|
||||
const auto converted = img.scaled(320, 240, Qt::AspectRatioMode::IgnoreAspectRatio,
|
||||
Qt::TransformationMode::SmoothTransformation);
|
||||
ui->preview_box->setPixmap(QPixmap::fromImage(converted));
|
||||
pending_snapshots = 0;
|
||||
}
|
||||
|
||||
void ConfigureCamera::changeEvent(QEvent* event) {
|
||||
|
||||
@@ -44,6 +44,8 @@ private:
|
||||
|
||||
InputCommon::InputSubsystem* input_subsystem;
|
||||
|
||||
bool is_virtual_camera;
|
||||
int pending_snapshots;
|
||||
std::unique_ptr<QCamera> camera;
|
||||
std::unique_ptr<QCameraImageCapture> camera_capture;
|
||||
std::unique_ptr<QTimer> camera_timer;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "ui_configure_input.h"
|
||||
#include "ui_configure_input_advanced.h"
|
||||
#include "ui_configure_input_player.h"
|
||||
#include "yuzu/configuration/configure_camera.h"
|
||||
#include "yuzu/configuration/configure_debug_controller.h"
|
||||
#include "yuzu/configuration/configure_input.h"
|
||||
#include "yuzu/configuration/configure_input_advanced.h"
|
||||
@@ -163,6 +164,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
|
||||
[this, input_subsystem, &hid_core] {
|
||||
CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core);
|
||||
});
|
||||
connect(advanced, &ConfigureInputAdvanced::CallCameraDialog,
|
||||
[this, input_subsystem, &hid_core] {
|
||||
CallConfigureDialog<ConfigureCamera>(*this, input_subsystem);
|
||||
});
|
||||
|
||||
connect(ui->vibrationButton, &QPushButton::clicked,
|
||||
[this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); });
|
||||
|
||||
@@ -89,6 +89,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
|
||||
[this] { CallMotionTouchConfigDialog(); });
|
||||
connect(ui->ring_controller_configure, &QPushButton::clicked, this,
|
||||
[this] { CallRingControllerDialog(); });
|
||||
connect(ui->camera_configure, &QPushButton::clicked, this, [this] { CallCameraDialog(); });
|
||||
|
||||
#ifndef _WIN32
|
||||
ui->enable_raw_input->setVisible(false);
|
||||
@@ -136,6 +137,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
|
||||
Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
|
||||
Settings::values.controller_navigation = ui->controller_navigation->isChecked();
|
||||
Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked();
|
||||
Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked();
|
||||
}
|
||||
|
||||
void ConfigureInputAdvanced::LoadConfiguration() {
|
||||
@@ -169,6 +171,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
|
||||
ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
|
||||
ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue());
|
||||
ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue());
|
||||
ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue());
|
||||
|
||||
UpdateUIEnabled();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ signals:
|
||||
void CallTouchscreenConfigDialog();
|
||||
void CallMotionTouchConfigDialog();
|
||||
void CallRingControllerDialog();
|
||||
void CallCameraDialog();
|
||||
|
||||
private:
|
||||
void changeEvent(QEvent* event) override;
|
||||
|
||||
@@ -2617,6 +2617,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="enable_ir_sensor">
|
||||
<property name="text">
|
||||
<string>Infrared Camera</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QPushButton" name="camera_configure">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -147,6 +147,10 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size
|
||||
ui->progress_bar->setMaximum(static_cast<int>(total));
|
||||
previous_total = total;
|
||||
}
|
||||
// Reset the progress bar ranges if compilation is done
|
||||
if (stage == VideoCore::LoadCallbackStage::Complete) {
|
||||
ui->progress_bar->setRange(0, 0);
|
||||
}
|
||||
|
||||
QString estimate;
|
||||
// If theres a drastic slowdown in the rate, then display an estimate
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#ifdef __APPLE__
|
||||
#include <unistd.h> // for chdir
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <csignal>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
|
||||
#include "applets/qt_controller.h"
|
||||
@@ -259,6 +263,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||
config{std::make_unique<Config>(*system)},
|
||||
vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
|
||||
provider{std::make_unique<FileSys::ManualContentProvider>()} {
|
||||
#ifdef __linux__
|
||||
SetupSigInterrupts();
|
||||
#endif
|
||||
|
||||
Common::Log::Initialize();
|
||||
LoadTranslation();
|
||||
|
||||
@@ -376,6 +384,8 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||
SDL_EnableScreenSaver();
|
||||
#endif
|
||||
|
||||
SetupPrepareForSleep();
|
||||
|
||||
Common::Log::Start();
|
||||
|
||||
QStringList args = QApplication::arguments();
|
||||
@@ -460,6 +470,11 @@ GMainWindow::~GMainWindow() {
|
||||
if (render_window->parent() == nullptr) {
|
||||
delete render_window;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
::close(sig_interrupt_fds[0]);
|
||||
::close(sig_interrupt_fds[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GMainWindow::RegisterMetaTypes() {
|
||||
@@ -1285,6 +1300,43 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::SetupPrepareForSleep() {
|
||||
#ifdef __linux__
|
||||
auto bus = QDBusConnection::systemBus();
|
||||
if (bus.isConnected()) {
|
||||
const bool success = bus.connect(
|
||||
QStringLiteral("org.freedesktop.login1"), QStringLiteral("/org/freedesktop/login1"),
|
||||
QStringLiteral("org.freedesktop.login1.Manager"), QStringLiteral("PrepareForSleep"),
|
||||
QStringLiteral("b"), this, SLOT(OnPrepareForSleep(bool)));
|
||||
|
||||
if (!success) {
|
||||
LOG_WARNING(Frontend, "Couldn't register PrepareForSleep signal");
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Frontend, "QDBusConnection system bus is not connected");
|
||||
}
|
||||
#endif // __linux__
|
||||
}
|
||||
|
||||
void GMainWindow::OnPrepareForSleep(bool prepare_sleep) {
|
||||
if (emu_thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prepare_sleep) {
|
||||
if (emu_thread->IsRunning()) {
|
||||
auto_paused = true;
|
||||
OnPauseGame();
|
||||
}
|
||||
} else {
|
||||
if (!emu_thread->IsRunning() && auto_paused) {
|
||||
auto_paused = false;
|
||||
RequestGameResume();
|
||||
OnStartGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) {
|
||||
if (!QDBusConnection::sessionBus().isConnected()) {
|
||||
@@ -1324,6 +1376,52 @@ static void ReleaseWakeLockLinux(QDBusObjectPath lock) {
|
||||
QString::fromLatin1("org.freedesktop.portal.Request"));
|
||||
unlocker.call(QString::fromLatin1("Close"));
|
||||
}
|
||||
|
||||
std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0};
|
||||
|
||||
void GMainWindow::SetupSigInterrupts() {
|
||||
if (sig_interrupt_fds[2] == 1) {
|
||||
return;
|
||||
}
|
||||
socketpair(AF_UNIX, SOCK_STREAM, 0, sig_interrupt_fds.data());
|
||||
sig_interrupt_fds[2] = 1;
|
||||
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = &GMainWindow::HandleSigInterrupt;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESETHAND;
|
||||
sigaction(SIGINT, &sa, nullptr);
|
||||
sigaction(SIGTERM, &sa, nullptr);
|
||||
|
||||
sig_interrupt_notifier = new QSocketNotifier(sig_interrupt_fds[1], QSocketNotifier::Read, this);
|
||||
connect(sig_interrupt_notifier, &QSocketNotifier::activated, this,
|
||||
&GMainWindow::OnSigInterruptNotifierActivated);
|
||||
connect(this, &GMainWindow::SigInterrupt, this, &GMainWindow::close);
|
||||
}
|
||||
|
||||
void GMainWindow::HandleSigInterrupt(int sig) {
|
||||
if (sig == SIGINT) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Calling into Qt directly from a signal handler is not safe,
|
||||
// so wake up a QSocketNotifier with this hacky write call instead.
|
||||
char a = 1;
|
||||
int ret = write(sig_interrupt_fds[0], &a, sizeof(a));
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
void GMainWindow::OnSigInterruptNotifierActivated() {
|
||||
sig_interrupt_notifier->setEnabled(false);
|
||||
|
||||
char a;
|
||||
int ret = read(sig_interrupt_fds[1], &a, sizeof(a));
|
||||
(void)ret;
|
||||
|
||||
sig_interrupt_notifier->setEnabled(true);
|
||||
|
||||
emit SigInterrupt();
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
void GMainWindow::PreventOSSleep() {
|
||||
@@ -1541,6 +1639,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
|
||||
mouse_hide_timer.start();
|
||||
}
|
||||
|
||||
render_window->InitializeCamera();
|
||||
|
||||
std::string title_name;
|
||||
std::string title_version;
|
||||
const auto res = system->GetGameName(title_name);
|
||||
@@ -1622,6 +1722,7 @@ void GMainWindow::ShutdownGame() {
|
||||
tas_label->clear();
|
||||
input_subsystem->GetTas()->Stop();
|
||||
OnTasStateChanged();
|
||||
render_window->FinalizeCamera();
|
||||
|
||||
// Enable all controllers
|
||||
system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
|
||||
@@ -2861,6 +2962,12 @@ void GMainWindow::OnConfigure() {
|
||||
mouse_hide_timer.start();
|
||||
}
|
||||
|
||||
// Restart camera config
|
||||
if (emulation_running) {
|
||||
render_window->FinalizeCamera();
|
||||
render_window->InitializeCamera();
|
||||
}
|
||||
|
||||
if (!UISettings::values.has_broken_vulkan) {
|
||||
renderer_status_button->setEnabled(!emulation_running);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ signals:
|
||||
void WebBrowserExtractOfflineRomFS();
|
||||
void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
|
||||
|
||||
void SigInterrupt();
|
||||
|
||||
public slots:
|
||||
void OnLoadComplete();
|
||||
void OnExecuteProgram(std::size_t program_index);
|
||||
@@ -200,6 +202,8 @@ private:
|
||||
void ConnectMenuEvents();
|
||||
void UpdateMenuState();
|
||||
|
||||
void SetupPrepareForSleep();
|
||||
|
||||
void PreventOSSleep();
|
||||
void AllowOSSleep();
|
||||
|
||||
@@ -247,12 +251,19 @@ private:
|
||||
void RequestGameResume();
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
#ifdef __linux__
|
||||
void SetupSigInterrupts();
|
||||
static void HandleSigInterrupt(int);
|
||||
void OnSigInterruptNotifierActivated();
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
void OnStartGame();
|
||||
void OnRestartGame();
|
||||
void OnPauseGame();
|
||||
void OnPauseContinueGame();
|
||||
void OnStopGame();
|
||||
void OnPrepareForSleep(bool prepare_sleep);
|
||||
void OnMenuReportCompatibility();
|
||||
void OnOpenModsPage();
|
||||
void OnOpenQuickstartGuide();
|
||||
@@ -415,6 +426,9 @@ private:
|
||||
bool is_tas_recording_dialog_active{};
|
||||
|
||||
#ifdef __linux__
|
||||
QSocketNotifier* sig_interrupt_notifier;
|
||||
static std::array<int, 3> sig_interrupt_fds;
|
||||
|
||||
QDBusObjectPath wake_lock{};
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user