mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-23 12:23:41 +00:00
Merge branch 'controller-crash-grid-view-memory-leak' into 'master'
fix: Prevent controller crashes and memory leaks in game list grid view See merge request citron/rewrite!36
This commit is contained in:
@@ -203,6 +203,13 @@ void GameList::FilterGridView(const QString& filter_text) {
|
|||||||
// Repopulate the grid view with filtered items
|
// Repopulate the grid view with filtered items
|
||||||
QStandardItemModel* hierarchical_model = item_model;
|
QStandardItemModel* hierarchical_model = item_model;
|
||||||
|
|
||||||
|
// Delete the previous flat model if it exists to prevent memory leaks
|
||||||
|
if (QAbstractItemModel* old_model = list_view->model()) {
|
||||||
|
if (old_model != item_model) {
|
||||||
|
old_model->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new flat model for grid view
|
// Create a new flat model for grid view
|
||||||
QStandardItemModel* flat_model = new QStandardItemModel(this);
|
QStandardItemModel* flat_model = new QStandardItemModel(this);
|
||||||
|
|
||||||
@@ -470,9 +477,19 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
|||||||
if (!this->isActiveWindow()) {
|
if (!this->isActiveWindow()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only send events to visible and properly initialized views
|
||||||
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
||||||
|
|
||||||
|
if (tree_view->isVisible() && tree_view->model()) {
|
||||||
QCoreApplication::postEvent(tree_view, event);
|
QCoreApplication::postEvent(tree_view, event);
|
||||||
QCoreApplication::postEvent(list_view, event);
|
}
|
||||||
|
|
||||||
|
if (list_view->isVisible() && list_view->model()) {
|
||||||
|
// Create a new event for the list view to avoid double deletion
|
||||||
|
QKeyEvent* list_event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
||||||
|
QCoreApplication::postEvent(list_view, list_event);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// We must register all custom types with the Qt Automoc system so that we are able to use
|
// We must register all custom types with the Qt Automoc system so that we are able to use
|
||||||
@@ -496,6 +513,13 @@ void GameList::UnloadController() {
|
|||||||
|
|
||||||
GameList::~GameList() {
|
GameList::~GameList() {
|
||||||
UnloadController();
|
UnloadController();
|
||||||
|
|
||||||
|
// Clean up any custom models that might have been created for grid view
|
||||||
|
if (QAbstractItemModel* current_model = list_view->model()) {
|
||||||
|
if (current_model != item_model) {
|
||||||
|
current_model->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::SetFilterFocus() {
|
void GameList::SetFilterFocus() {
|
||||||
@@ -1114,19 +1138,32 @@ void GameList::SetViewMode(bool grid_view) {
|
|||||||
PopulateGridView();
|
PopulateGridView();
|
||||||
tree_view->setVisible(false);
|
tree_view->setVisible(false);
|
||||||
list_view->setVisible(true);
|
list_view->setVisible(true);
|
||||||
|
// Only set current index if the model has items
|
||||||
|
if (list_view->model() && list_view->model()->rowCount() > 0) {
|
||||||
list_view->setCurrentIndex(list_view->model()->index(0, 0));
|
list_view->setCurrentIndex(list_view->model()->index(0, 0));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Restore the hierarchical model for tree view
|
// Restore the hierarchical model for tree view
|
||||||
list_view->setVisible(false);
|
list_view->setVisible(false);
|
||||||
tree_view->setVisible(true);
|
tree_view->setVisible(true);
|
||||||
|
// Only set current index if the model has items
|
||||||
|
if (item_model && item_model->rowCount() > 0) {
|
||||||
tree_view->setCurrentIndex(item_model->index(0, 0));
|
tree_view->setCurrentIndex(item_model->index(0, 0));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::PopulateGridView() {
|
void GameList::PopulateGridView() {
|
||||||
// Store the current hierarchical model
|
// Store the current hierarchical model
|
||||||
QStandardItemModel* hierarchical_model = item_model;
|
QStandardItemModel* hierarchical_model = item_model;
|
||||||
|
|
||||||
|
// Delete the previous flat model if it exists to prevent memory leaks
|
||||||
|
if (QAbstractItemModel* old_model = list_view->model()) {
|
||||||
|
if (old_model != item_model) {
|
||||||
|
old_model->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new flat model for grid view
|
// Create a new flat model for grid view
|
||||||
QStandardItemModel* flat_model = new QStandardItemModel(this);
|
QStandardItemModel* flat_model = new QStandardItemModel(this);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/settings_input.h"
|
#include "common/settings_input.h"
|
||||||
@@ -42,6 +43,12 @@ void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerTyp
|
|||||||
if (!Settings::values.controller_navigation) {
|
if (!Settings::values.controller_navigation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety check: ensure controllers are properly initialized
|
||||||
|
if (!is_controller_set || !player1_controller || !handheld_controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == Core::HID::ControllerTriggerType::Button) {
|
if (type == Core::HID::ControllerTriggerType::Button) {
|
||||||
ControllerUpdateButton();
|
ControllerUpdateButton();
|
||||||
return;
|
return;
|
||||||
@@ -54,6 +61,11 @@ void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControllerNavigation::ControllerUpdateButton() {
|
void ControllerNavigation::ControllerUpdateButton() {
|
||||||
|
// Safety check: ensure controllers are properly initialized
|
||||||
|
if (!is_controller_set || !player1_controller || !handheld_controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto controller_type = player1_controller->GetNpadStyleIndex();
|
const auto controller_type = player1_controller->GetNpadStyleIndex();
|
||||||
const auto& player1_buttons = player1_controller->GetButtonsValues();
|
const auto& player1_buttons = player1_controller->GetButtonsValues();
|
||||||
const auto& handheld_buttons = handheld_controller->GetButtonsValues();
|
const auto& handheld_buttons = handheld_controller->GetButtonsValues();
|
||||||
@@ -91,6 +103,11 @@ void ControllerNavigation::ControllerUpdateButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControllerNavigation::ControllerUpdateStick() {
|
void ControllerNavigation::ControllerUpdateStick() {
|
||||||
|
// Safety check: ensure controllers are properly initialized
|
||||||
|
if (!is_controller_set || !player1_controller || !handheld_controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto controller_type = player1_controller->GetNpadStyleIndex();
|
const auto controller_type = player1_controller->GetNpadStyleIndex();
|
||||||
const auto& player1_sticks = player1_controller->GetSticksValues();
|
const auto& player1_sticks = player1_controller->GetSticksValues();
|
||||||
const auto& handheld_sticks = player1_controller->GetSticksValues();
|
const auto& handheld_sticks = player1_controller->GetSticksValues();
|
||||||
|
|||||||
Reference in New Issue
Block a user