Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/platform/qt/AssetTile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ int AssetTile::customLocation(const QString&) {
return layout()->indexOf(m_ui.line);
}

void AssetTile::setController(std::shared_ptr<CoreController> controller) {
void AssetTile::onCoreAttached(std::shared_ptr<CoreController> controller) {
m_cacheSet = controller->graphicCaches();
switch (controller->platform()) {
#ifdef M_CORE_GBA
Expand Down
6 changes: 4 additions & 2 deletions src/platform/qt/AssetTile.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once

#include "CorePointer.h"
#include "ui_AssetTile.h"

#include <memory>
Expand All @@ -15,12 +16,11 @@ namespace QGBA {

class CoreController;

class AssetTile : public AssetInfo {
class AssetTile : public AssetInfo, public CoreConsumer {
Q_OBJECT

public:
AssetTile(QWidget* parent = nullptr);
void setController(std::shared_ptr<CoreController>);
QImage activeTile() const { return m_activeTile; }

public slots:
Expand All @@ -35,6 +35,8 @@ public slots:
int customLocation(const QString& id = {}) override;

private:
void onCoreAttached(std::shared_ptr<CoreController>);

Ui::AssetTile m_ui;

mCacheSet* m_cacheSet;
Expand Down
11 changes: 6 additions & 5 deletions src/platform/qt/AssetView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "AssetView.h"

#include "CoreController.h"
#include "CorePointerSource.h"

#include <QTimer>

Expand All @@ -21,18 +22,18 @@

using namespace QGBA;

AssetView::AssetView(std::shared_ptr<CoreController> controller, QWidget* parent)
AssetView::AssetView(CorePointerSource* controller, QWidget* parent)
: QWidget(parent)
, m_cacheSet(controller->graphicCaches())
, m_controller(controller)
, CoreConsumer(controller)
, m_cacheSet(m_controller->graphicCaches())
{
m_updateTimer.setSingleShot(true);
m_updateTimer.setInterval(1);
connect(&m_updateTimer, &QTimer::timeout, this, static_cast<void(AssetView::*)()>(&AssetView::updateTiles));

connect(controller.get(), &CoreController::frameAvailable, &m_updateTimer,
connect(m_controller.get(), &CoreController::frameAvailable, &m_updateTimer,
static_cast<void(QTimer::*)()>(&QTimer::start));
connect(controller.get(), &CoreController::stopping, &m_updateTimer, &QTimer::stop);
connect(m_controller.get(), &CoreController::stopping, &m_updateTimer, &QTimer::stop);
}

void AssetView::updateTiles() {
Expand Down
7 changes: 4 additions & 3 deletions src/platform/qt/AssetView.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,26 @@

#include <memory>

#include "CorePointer.h"

struct mMapCacheEntry;

namespace QGBA {

class CoreController;

class AssetView : public QWidget {
class AssetView : public QWidget, public CoreConsumer {
Q_OBJECT

public:
AssetView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
AssetView(CorePointerSource* controller, QWidget* parent = nullptr);

protected slots:
void updateTiles();
void updateTiles(bool force);

protected:
mCacheSet* const m_cacheSet;
std::shared_ptr<CoreController> m_controller;

struct ObjInfo {
unsigned tile;
Expand Down
4 changes: 3 additions & 1 deletion src/platform/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ set(SOURCE_FILES
CheckBoxDelegate.cpp
ConfigController.cpp
ColorPicker.cpp
CoreManager.cpp
CoreController.cpp
CoreManager.cpp
CorePointer.cpp
CorePointerSource.cpp
Display.cpp
DisplayGL.cpp
DisplayQt.cpp
Expand Down
75 changes: 75 additions & 0 deletions src/platform/qt/CorePointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* Copyright (c) 2013-2025 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CorePointer.h"

#include "CoreController.h"
#include "CorePointerSource.h"

using namespace QGBA;

CoreConsumer::CoreConsumer(CorePointerSource* source)
: m_controller(this)
{
if (source) {
m_controller.setSource(source);
}
}

void CoreConsumer::onCoreDetached(std::shared_ptr<CoreController>) {
// default detach behavior is to do nothing
}

void CoreConsumer::onCoreAttached(std::shared_ptr<CoreController>) {
// default attach behavior is to do nothing
}

CorePointer::CorePointer(CoreConsumer* consumer) {
m_consumer = consumer;
}

CorePointer::~CorePointer() {
if (m_source) {
m_source->removePointer(this);
}
}

void CorePointer::setSource(CorePointerSource* source) {
if (m_source) {
emitDetach();
m_source->removePointer(this);
}
m_source = source;
if (source) {
source->addPointer(this);
emitAttach();
}
}

CoreController* CorePointer::get() const {
if (!m_source) {
return nullptr;
}
return m_source->get();
}

std::shared_ptr<CoreController> CorePointer::getShared() const {
if (!m_source) {
return nullptr;
}
return *m_source;
}

void CorePointer::emitAttach() {
if (m_consumer && *m_source) {
m_consumer->onCoreAttached(*m_source);
}
}

void CorePointer::emitDetach() {
if (m_consumer && *m_source) {
m_consumer->onCoreDetached(*m_source);
}
}
57 changes: 57 additions & 0 deletions src/platform/qt/CorePointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Copyright (c) 2013-2025 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once

#include <memory>

namespace QGBA {

class CoreConsumer;
class CoreController;
class CorePointerSource;

class CorePointer {
friend class CorePointerSource;

public:
CorePointer() = default;
explicit CorePointer(CoreConsumer* consumer);
~CorePointer();

void setSource(CorePointerSource* source);
inline CorePointerSource* source() const { return m_source; }

CoreController* get() const;
std::shared_ptr<CoreController> getShared() const;
inline operator bool() const { return get(); }
inline CoreController* operator->() const { return get(); }
inline operator std::shared_ptr<CoreController>() const { return getShared(); }

private:
void emitAttach();
void emitDetach();

CoreConsumer* m_consumer = nullptr;
CorePointerSource* m_source = nullptr;
};

class CoreConsumer {
friend class CorePointer;

public:
CoreConsumer(CorePointerSource* source = nullptr);
virtual ~CoreConsumer() {}

inline void setCoreSource(CorePointerSource* source) { m_controller.setSource(source); }

protected:
CorePointer m_controller;

virtual void onCoreDetached(std::shared_ptr<CoreController>);
virtual void onCoreAttached(std::shared_ptr<CoreController>);
};

}
62 changes: 62 additions & 0 deletions src/platform/qt/CorePointerSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* Copyright (c) 2013-2025 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CorePointerSource.h"

#include "CoreController.h"
#include "CorePointer.h"

using namespace QGBA;

/**
* CorePointerSource is a layer of indirection around a pointer to CoreController.
* CorePointer instances can attach to a CorePointerSource in order to always refer
* to the same underlying CoreController instance as the source, even if the
* controller is replaced.
*/

CorePointerSource::CorePointerSource(std::shared_ptr<CoreController> controller) {
setController(controller);
}

CorePointerSource::~CorePointerSource() {
for (CorePointer* consumer : m_pointers) {
consumer->m_source = nullptr;
}
}

void CorePointerSource::setController(std::shared_ptr<CoreController> controller) {
if (controller == m_controller) {
return;
}
for (CorePointer* ptr : m_pointers) {
ptr->emitDetach();
}
m_controller = controller;
for (CorePointer* ptr : m_pointers) {
ptr->emitAttach();
}
}

CoreController* CorePointerSource::get() const {
return m_controller.get();
}

void CorePointerSource::addPointer(CorePointer* consumer) {
m_pointers.insert(consumer);
}

void CorePointerSource::removePointer(CorePointer* consumer) {
m_pointers.erase(consumer);
}

void CorePointerSource::swap(std::shared_ptr<CoreController>& controller) {
m_controller.swap(controller);
}

CorePointerSource& CorePointerSource::operator=(const std::shared_ptr<CoreController>& controller) {
setController(controller);
return *this;
}
39 changes: 39 additions & 0 deletions src/platform/qt/CorePointerSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright (c) 2013-2025 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once

#include <memory>
#include <unordered_set>

namespace QGBA {

class CoreController;
class CorePointer;

class CorePointerSource {
public:
CorePointerSource() = default;
CorePointerSource(std::shared_ptr<CoreController> controller);
virtual ~CorePointerSource();

void addPointer(CorePointer* ptr);
void removePointer(CorePointer* ptr);

void setController(std::shared_ptr<CoreController> controller);
CoreController* get() const;
inline CoreController* operator->() const { return get(); }
inline operator std::shared_ptr<CoreController>&() { return m_controller; }
inline operator bool() const { return get(); }
CorePointerSource& operator=(const std::shared_ptr<CoreController>& controller);

void swap(std::shared_ptr<CoreController>& controller);

private:
std::shared_ptr<CoreController> m_controller;
std::unordered_set<CorePointer*> m_pointers;
};

}
12 changes: 6 additions & 6 deletions src/platform/qt/DebuggerConsoleController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ DebuggerConsoleController::DebuggerConsoleController(QObject* parent)
}

void DebuggerConsoleController::enterLine(const QString& line) {
CoreController::Interrupter interrupter(m_gameController);
CoreController::Interrupter interrupter(m_controller);
QMutexLocker lock(&m_mutex);
m_lines.append(line);
if (m_cliDebugger.d.p && m_cliDebugger.d.p->state == DEBUGGER_RUNNING) {
Expand All @@ -46,7 +46,7 @@ void DebuggerConsoleController::enterLine(const QString& line) {

void DebuggerConsoleController::detach() {
{
CoreController::Interrupter interrupter(m_gameController);
CoreController::Interrupter interrupter(m_controller);
QMutexLocker lock(&m_mutex);
if (m_cliDebugger.d.p && m_cliDebugger.d.p->state != DEBUGGER_SHUTDOWN) {
m_lines.append(QString());
Expand All @@ -58,9 +58,9 @@ void DebuggerConsoleController::detach() {
}

void DebuggerConsoleController::attachInternal() {
CoreController::Interrupter interrupter(m_gameController);
CoreController::Interrupter interrupter(m_controller);
QMutexLocker lock(&m_mutex);
mCore* core = m_gameController->thread()->core;
mCore* core = m_controller->thread()->core;
CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend);
CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core));
}
Expand Down Expand Up @@ -123,7 +123,7 @@ void DebuggerConsoleController::lineAppend(struct CLIDebuggerBackend* be, const
const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be, size_t* len) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
CoreController::Interrupter interrupter(self->m_gameController);
CoreController::Interrupter interrupter(self->m_controller);
QMutexLocker lock(&self->m_mutex);
if (self->m_history.isEmpty()) {
return "i";
Expand All @@ -136,7 +136,7 @@ const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be
void DebuggerConsoleController::historyAppend(struct CLIDebuggerBackend* be, const char* line) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
CoreController::Interrupter interrupter(self->m_gameController);
CoreController::Interrupter interrupter(self->m_controller);
QMutexLocker lock(&self->m_mutex);
self->m_history.append(QString::fromUtf8(line));
}
Expand Down
Loading