diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b57b0e32c..1fce7cfd3 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include "citra_qt/bootmanager.h" +#include "citra_qt/main.h" #include "common/microprofile.h" #include "common/scm_rev.h" #include "core/3ds.h" @@ -31,6 +33,15 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor EmuThread::~EmuThread() = default; +static GMainWindow* GetMainWindow() { + for (QWidget* w : qApp->topLevelWidgets()) { + if (GMainWindow* main = qobject_cast(w)) { + return main; + } + } + return nullptr; +} + void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); Frontend::ScopeAcquireContext scope(core_context); @@ -138,6 +149,15 @@ bool OpenGLWindow::event(QEvent* event) { case QEvent::InputMethodQuery: case QEvent::TouchCancel: return QCoreApplication::sendEvent(event_handler, event); + case QEvent::Drop: + GetMainWindow()->DropAction(static_cast(event)); + return true; + case QEvent::DragResponse: + case QEvent::DragEnter: + case QEvent::DragLeave: + case QEvent::DragMove: + GetMainWindow()->AcceptDropEvent(static_cast(event)); + return true; default: return QWindow::event(event); } @@ -298,15 +318,19 @@ void GRenderWindow::TouchEndEvent() { } bool GRenderWindow::event(QEvent* event) { - if (event->type() == QEvent::TouchBegin) { + switch (event->type()) { + case QEvent::TouchBegin: TouchBeginEvent(static_cast(event)); return true; - } else if (event->type() == QEvent::TouchUpdate) { + case QEvent::TouchUpdate: TouchUpdateEvent(static_cast(event)); return true; - } else if (event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) { + case QEvent::TouchEnd: + case QEvent::TouchCancel: TouchEndEvent(); return true; + default: + break; } return QWidget::event(event); diff --git a/src/citra_qt/configuration/configure_hotkeys.cpp b/src/citra_qt/configuration/configure_hotkeys.cpp index 1479283f0..238b2e8c6 100644 --- a/src/citra_qt/configuration/configure_hotkeys.cpp +++ b/src/citra_qt/configuration/configure_hotkeys.cpp @@ -105,10 +105,10 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) { QStandardItem* action = parent->child(key_column_id, 0); QStandardItem* keyseq = parent->child(key_column_id, 1); - for (auto& [group, sub_actions] : registry.hotkey_groups) { + for (auto & [group, sub_actions] : registry.hotkey_groups) { if (group != parent->text()) continue; - for (auto& [action_name, hotkey] : sub_actions) { + for (auto & [action_name, hotkey] : sub_actions) { if (action_name != action->text()) continue; hotkey.keyseq = QKeySequence(keyseq->text()); diff --git a/src/citra_qt/configuration/configure_web.cpp b/src/citra_qt/configuration/configure_web.cpp index cc7ca675f..266e04ffe 100644 --- a/src/citra_qt/configuration/configure_web.cpp +++ b/src/citra_qt/configuration/configure_web.cpp @@ -127,11 +127,10 @@ void ConfigureWeb::OnLoginChanged() { void ConfigureWeb::VerifyLogin() { ui->button_verify_login->setDisabled(true); ui->button_verify_login->setText(tr("Verifying...")); - verify_watcher.setFuture(QtConcurrent::run( - [username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), - token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] { - return Core::VerifyLogin(username, token); - })); + verify_watcher.setFuture(QtConcurrent::run([ + username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), + token = TokenFromDisplayToken(ui->edit_token->text().toStdString()) + ] { return Core::VerifyLogin(username, token); })); } void ConfigureWeb::OnLoginVerified() { diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 52c1ba436..8830c9e3f 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1869,14 +1869,33 @@ void GMainWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } -static bool IsSingleFileDropEvent(QDropEvent* event) { - const QMimeData* mimeData = event->mimeData(); - return mimeData->hasUrls() && mimeData->urls().length() == 1; +static bool IsSingleFileDropEvent(const QMimeData* mime) { + return mime->hasUrls() && mime->urls().length() == 1; } -void GMainWindow::dropEvent(QDropEvent* event) { - if (!IsSingleFileDropEvent(event)) { - return; +static const std::array AcceptedExtensions = {"cci", "3ds", "cxi", "bin", + "3dsx", "app", "elf", "axf"}; + +static bool IsCorrectFileExtension(const QMimeData* mime) { + const QString& filename = mime->urls().at(0).toLocalFile(); + return std::find(AcceptedExtensions.begin(), AcceptedExtensions.end(), + QFileInfo(filename).suffix().toStdString()) != AcceptedExtensions.end(); +} + +static bool IsAcceptableDropEvent(QDropEvent* event) { + return IsSingleFileDropEvent(event->mimeData()) && IsCorrectFileExtension(event->mimeData()); +} + +void GMainWindow::AcceptDropEvent(QDropEvent* event) { + if (IsAcceptableDropEvent(event)) { + event->setDropAction(Qt::DropAction::LinkAction); + event->accept(); + } +} + +bool GMainWindow::DropAction(QDropEvent* event) { + if (!IsAcceptableDropEvent(event)) { + return false; } const QMimeData* mime_data = event->mimeData(); @@ -1891,16 +1910,19 @@ void GMainWindow::dropEvent(QDropEvent* event) { BootGame(filename); } } + return true; +} + +void GMainWindow::dropEvent(QDropEvent* event) { + DropAction(event); } void GMainWindow::dragEnterEvent(QDragEnterEvent* event) { - if (IsSingleFileDropEvent(event)) { - event->acceptProposedAction(); - } + AcceptDropEvent(event); } void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { - event->acceptProposedAction(); + AcceptDropEvent(event); } bool GMainWindow::ConfirmChangeGame() { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 9c7888056..0fa04f5b8 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -41,6 +41,7 @@ class QProgressBar; class RegistersWidget; class Updater; class WaitTreeWidget; + namespace DiscordRPC { class DiscordInterface; } @@ -69,8 +70,12 @@ public: GameList* game_list; std::unique_ptr discord_rpc; + bool DropAction(QDropEvent* event); + void AcceptDropEvent(QDropEvent* event); + public slots: void OnAppFocusStateChanged(Qt::ApplicationState state); + signals: /** @@ -78,8 +83,8 @@ signals: * about to start. At this time, the core system emulation has been initialized, and all * emulation handles and memory should be valid. * - * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to - * access/change emulation state). + * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need + * to access/change emulation state). */ void EmulationStarting(EmuThread* emu_thread);