Put each DeviceEngine in its own thread, don't pretend to be a QAbstractItemModel (it's annoying and not at all thread-safe), add a debugging class to listen to and print events.
This commit is contained in:
parent
2ef1fe5ac1
commit
b423350208
|
@ -54,6 +54,7 @@ set(SOURCES
|
|||
|
||||
devices/device.cpp
|
||||
devices/deviceengine.cpp
|
||||
devices/devicetest.cpp
|
||||
devices/filesystemdeviceengine.cpp
|
||||
|
||||
engines/enginebase.cpp
|
||||
|
@ -174,6 +175,7 @@ set(HEADERS
|
|||
|
||||
devices/device.h
|
||||
devices/deviceengine.h
|
||||
devices/devicetest.h
|
||||
devices/filesystemdeviceengine.h
|
||||
|
||||
engines/enginebase.h
|
||||
|
|
|
@ -16,7 +16,30 @@
|
|||
|
||||
#include "deviceengine.h"
|
||||
|
||||
DeviceEngine::DeviceEngine(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
#include <QThread>
|
||||
#include <QtDebug>
|
||||
|
||||
DeviceEngine::DeviceEngine()
|
||||
: thread_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
DeviceEngine::~DeviceEngine() {
|
||||
qDebug() << __PRETTY_FUNCTION__;
|
||||
if (thread_) {
|
||||
thread_->quit();
|
||||
thread_->wait(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceEngine::Start() {
|
||||
thread_ = new QThread;
|
||||
connect(thread_, SIGNAL(started()), SLOT(ThreadStarted()));
|
||||
|
||||
moveToThread(thread_);
|
||||
thread_->start();
|
||||
}
|
||||
|
||||
void DeviceEngine::ThreadStarted() {
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -19,24 +19,45 @@
|
|||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class DeviceEngine : public QAbstractItemModel {
|
||||
class DeviceEngine : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeviceEngine(QObject* parent = 0);
|
||||
DeviceEngine();
|
||||
~DeviceEngine();
|
||||
|
||||
enum Column {
|
||||
Column_UniqueID = 0,
|
||||
Column_FriendlyName,
|
||||
Column_Manufacturer,
|
||||
Column_Model,
|
||||
Column_Capacity,
|
||||
Column_FreeSpace,
|
||||
enum Field {
|
||||
Field_UniqueID = 0,
|
||||
Field_FriendlyName,
|
||||
Field_Manufacturer,
|
||||
Field_Model,
|
||||
Field_Capacity,
|
||||
Field_FreeSpace,
|
||||
|
||||
LastDeviceEngineColumn
|
||||
LastDeviceEngineField
|
||||
};
|
||||
|
||||
virtual bool Init() = 0;
|
||||
// Tries to start the thread and initialise the engine. This object will be
|
||||
// moved to the new thread.
|
||||
void Start();
|
||||
|
||||
// Query information about the devices that are available. Thread-safe.
|
||||
virtual QStringList DeviceUniqueIDs() = 0;
|
||||
virtual QVariant DeviceInfo(const QString& id, int field) = 0;
|
||||
|
||||
signals:
|
||||
void DeviceAdded(const QString& id);
|
||||
void DeviceRemoved(const QString& id);
|
||||
void DeviceChanged(const QString& id);
|
||||
|
||||
protected:
|
||||
virtual void Init() = 0;
|
||||
|
||||
protected:
|
||||
QThread* thread_;
|
||||
|
||||
private slots:
|
||||
void ThreadStarted();
|
||||
};
|
||||
|
||||
#endif // DEVICEENGINE_H
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* This file is part of Clementine.
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "devicetest.h"
|
||||
#include "filesystemdeviceengine.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
DeviceTest::DeviceTest(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
DeviceEngine* engine = new FilesystemDeviceEngine;
|
||||
engines_ << engine;
|
||||
connect(engine, SIGNAL(DeviceAdded(QString)), SLOT(DeviceAdded(QString)));
|
||||
connect(engine, SIGNAL(DeviceRemoved(QString)), SLOT(DeviceRemoved(QString)));
|
||||
connect(engine, SIGNAL(DeviceChanged(QString)), SLOT(DeviceChanged(QString)));
|
||||
|
||||
engine->Start();
|
||||
}
|
||||
|
||||
DeviceTest::~DeviceTest() {
|
||||
qDeleteAll(engines_);
|
||||
}
|
||||
|
||||
void DeviceTest::DeviceAdded(const QString &id) {
|
||||
DeviceEngine* engine = qobject_cast<DeviceEngine*>(sender());
|
||||
|
||||
qDebug() << "Device added:" << id;
|
||||
for (int i=0 ; i<FilesystemDeviceEngine::LastFilesystemDeviceEngineField ; ++i) {
|
||||
qDebug() << i << engine->DeviceInfo(id, i);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceTest::DeviceRemoved(const QString &id) {
|
||||
qDebug() << "Device removed:" << id;
|
||||
}
|
||||
|
||||
void DeviceTest::DeviceChanged(const QString &id) {
|
||||
DeviceEngine* engine = qobject_cast<DeviceEngine*>(sender());
|
||||
|
||||
qDebug() << "Device changed:" << id;
|
||||
for (int i=0 ; i<FilesystemDeviceEngine::LastFilesystemDeviceEngineField ; ++i) {
|
||||
qDebug() << i << engine->DeviceInfo(id, i);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* This file is part of Clementine.
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEVICETEST_H
|
||||
#define DEVICETEST_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class DeviceEngine;
|
||||
|
||||
class DeviceTest : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeviceTest(QObject* parent = 0);
|
||||
~DeviceTest();
|
||||
|
||||
public slots:
|
||||
void DeviceAdded(const QString& id);
|
||||
void DeviceRemoved(const QString& id);
|
||||
void DeviceChanged(const QString& id);
|
||||
|
||||
private:
|
||||
QList<DeviceEngine*> engines_;
|
||||
};
|
||||
|
||||
#endif // DEVICETEST_H
|
|
@ -18,15 +18,21 @@
|
|||
#include "dbus/udisks.h"
|
||||
#include "dbus/udisksdevice.h"
|
||||
|
||||
FilesystemDeviceEngine::FilesystemDeviceEngine(QObject *parent)
|
||||
: DeviceEngine(parent)
|
||||
#include <QtDebug>
|
||||
|
||||
FilesystemDeviceEngine::FilesystemDeviceEngine()
|
||||
{
|
||||
}
|
||||
|
||||
FilesystemDeviceEngine::~FilesystemDeviceEngine() {
|
||||
qDebug() << __PRETTY_FUNCTION__;
|
||||
}
|
||||
|
||||
bool FilesystemDeviceEngine::Init() {
|
||||
QString FilesystemDeviceEngine::DeviceData::unique_id() const {
|
||||
return QString("%1 %2 %3 %4").arg(drive_serial, drive_vendor, drive_model).arg(device_size);
|
||||
}
|
||||
|
||||
void FilesystemDeviceEngine::Init() {
|
||||
interface_.reset(new OrgFreedesktopUDisksInterface(
|
||||
OrgFreedesktopUDisksInterface::staticInterfaceName(),
|
||||
"/org/freedesktop/UDisks", QDBusConnection::systemBus()));
|
||||
|
@ -34,71 +40,15 @@ bool FilesystemDeviceEngine::Init() {
|
|||
if (!interface_->isValid()) {
|
||||
qWarning() << "Error connecting to the DeviceKit-disks DBUS service";
|
||||
interface_.reset();
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
connect(interface_.get(), SIGNAL(DeviceAdded(QDBusObjectPath)), SLOT(DeviceAdded(QDBusObjectPath)));
|
||||
connect(interface_.get(), SIGNAL(DeviceRemoved(QDBusObjectPath)), SLOT(DeviceRemoved(QDBusObjectPath)));
|
||||
connect(interface_.get(), SIGNAL(DeviceChanged(QDBusObjectPath)), SLOT(DeviceChanged(QDBusObjectPath)));
|
||||
// Listen for changes
|
||||
connect(interface_.get(), SIGNAL(DeviceAdded(QDBusObjectPath)), SLOT(DBusDeviceAdded(QDBusObjectPath)));
|
||||
connect(interface_.get(), SIGNAL(DeviceRemoved(QDBusObjectPath)), SLOT(DBusDeviceRemoved(QDBusObjectPath)));
|
||||
connect(interface_.get(), SIGNAL(DeviceChanged(QDBusObjectPath)), SLOT(DBusDeviceChanged(QDBusObjectPath)));
|
||||
|
||||
Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
QModelIndex FilesystemDeviceEngine::index(int row, int column, const QModelIndex &parent) const {
|
||||
if (parent.isValid())
|
||||
return QModelIndex();
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
int FilesystemDeviceEngine::rowCount(const QModelIndex &parent) const {
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return device_info_.count();
|
||||
}
|
||||
|
||||
int FilesystemDeviceEngine::columnCount(const QModelIndex &parent) const {
|
||||
return LastFilesystemDeviceEngineColumn;
|
||||
}
|
||||
|
||||
QVariant FilesystemDeviceEngine::data(const QModelIndex &index, int role) const {
|
||||
const DeviceInfo& info = device_info_[index.row()];
|
||||
|
||||
switch (index.column()) {
|
||||
case Column_UniqueID:
|
||||
return info.unique_id();
|
||||
|
||||
case Column_FriendlyName:
|
||||
if (!info.device_presentation_name.isEmpty())
|
||||
return info.device_presentation_name;
|
||||
if (!info.drive_model.isEmpty() || !info.drive_vendor.isEmpty())
|
||||
return QString("%1 %2").arg(info.drive_vendor, info.drive_model);
|
||||
return info.drive_serial;
|
||||
|
||||
case Column_Manufacturer:
|
||||
return info.drive_vendor;
|
||||
|
||||
case Column_Model:
|
||||
return info.drive_model;
|
||||
|
||||
case Column_Capacity:
|
||||
return info.device_size;
|
||||
|
||||
case Column_FreeSpace:
|
||||
return QVariant();
|
||||
|
||||
case Column_DbusPath:
|
||||
return info.dbus_path;
|
||||
|
||||
case Column_MountPath:
|
||||
return info.device_mount_paths.isEmpty() ? QVariant() : info.device_mount_paths[0];
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void FilesystemDeviceEngine::Reset() {
|
||||
// Get all the devices currently attached
|
||||
QDBusPendingReply<QList<QDBusObjectPath> > reply = interface_->EnumerateDevices();
|
||||
reply.waitForFinished();
|
||||
|
||||
|
@ -107,30 +57,81 @@ void FilesystemDeviceEngine::Reset() {
|
|||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x040600
|
||||
emit beginResetModel();
|
||||
#endif
|
||||
|
||||
device_info_.clear();
|
||||
// Get information about each one
|
||||
QMap<QString, DeviceData> device_data;
|
||||
foreach (const QDBusObjectPath& path, reply.value()) {
|
||||
DeviceInfo info = ReadDeviceInfo(path);
|
||||
if (info.suitable)
|
||||
device_info_ << info;
|
||||
DeviceData data = ReadDeviceData(path);
|
||||
if (data.suitable)
|
||||
device_data[data.unique_id()] = data;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x040600
|
||||
emit endResetModel();
|
||||
#else
|
||||
reset();
|
||||
#endif
|
||||
// Update the internal cache
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
device_data_ = device_data;
|
||||
}
|
||||
|
||||
// Notify about the changes
|
||||
foreach (const QString& id, device_data.keys()) {
|
||||
emit DeviceAdded(id);
|
||||
}
|
||||
}
|
||||
|
||||
FilesystemDeviceEngine::DeviceInfo FilesystemDeviceEngine::ReadDeviceInfo(
|
||||
QStringList FilesystemDeviceEngine::DeviceUniqueIDs() {
|
||||
QMutexLocker l(&mutex_);
|
||||
return device_data_.keys();
|
||||
}
|
||||
|
||||
QVariant FilesystemDeviceEngine::DeviceInfo(const QString& id, int field) {
|
||||
DeviceData data;
|
||||
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
if (!device_data_.contains(id))
|
||||
return QVariant();
|
||||
data = device_data_[id];
|
||||
}
|
||||
|
||||
switch (field) {
|
||||
case Field_UniqueID:
|
||||
return data.unique_id();
|
||||
|
||||
case Field_FriendlyName:
|
||||
if (!data.device_presentation_name.isEmpty())
|
||||
return data.device_presentation_name;
|
||||
if (!data.drive_model.isEmpty() || !data.drive_vendor.isEmpty())
|
||||
return QString("%1 %2").arg(data.drive_vendor, data.drive_model);
|
||||
return data.drive_serial;
|
||||
|
||||
case Field_Manufacturer:
|
||||
return data.drive_vendor;
|
||||
|
||||
case Field_Model:
|
||||
return data.drive_model;
|
||||
|
||||
case Field_Capacity:
|
||||
return data.device_size;
|
||||
|
||||
case Field_FreeSpace:
|
||||
return QVariant();
|
||||
|
||||
case Field_DbusPath:
|
||||
return data.dbus_path;
|
||||
|
||||
case Field_MountPath:
|
||||
return data.device_mount_paths.isEmpty() ? QVariant() : data.device_mount_paths[0];
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
FilesystemDeviceEngine::DeviceData FilesystemDeviceEngine::ReadDeviceData(
|
||||
const QDBusObjectPath &path) const {
|
||||
DeviceInfo ret;
|
||||
DeviceData ret;
|
||||
|
||||
OrgFreedesktopUDisksDeviceInterface device(
|
||||
OrgFreedesktopUDisksDeviceInterface::staticInterfaceName(),
|
||||
OrgFreedesktopUDisksInterface::staticInterfaceName(),
|
||||
path.path(), QDBusConnection::systemBus());
|
||||
if (!device.isValid()) {
|
||||
qWarning() << "Error connecting to the device interface on" << path.path();
|
||||
|
@ -153,39 +154,63 @@ FilesystemDeviceEngine::DeviceInfo FilesystemDeviceEngine::ReadDeviceInfo(
|
|||
ret.device_presentation_name = device.devicePresentationName();
|
||||
ret.device_presentation_icon_name = device.devicePresentationIconName();
|
||||
ret.device_size = device.deviceSize();
|
||||
ret.device_mount_paths = device.deviceMountPaths();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FilesystemDeviceEngine::DeviceAdded(const QDBusObjectPath &path) {
|
||||
DeviceInfo info = ReadDeviceInfo(path);
|
||||
if (!info.suitable)
|
||||
void FilesystemDeviceEngine::DBusDeviceAdded(const QDBusObjectPath &path) {
|
||||
DeviceData data = ReadDeviceData(path);
|
||||
if (!data.suitable)
|
||||
return;
|
||||
|
||||
emit beginInsertRows(QModelIndex(), device_info_.count(), device_info_.count());
|
||||
device_info_ << info;
|
||||
emit endInsertRows();
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
device_data_[data.unique_id()] = data;
|
||||
}
|
||||
|
||||
emit DeviceAdded(data.unique_id());
|
||||
}
|
||||
|
||||
void FilesystemDeviceEngine::DeviceRemoved(const QDBusObjectPath &path) {
|
||||
QModelIndex index = FindDevice(path);
|
||||
if (!index.isValid())
|
||||
return;
|
||||
void FilesystemDeviceEngine::DBusDeviceRemoved(const QDBusObjectPath &path) {
|
||||
QString id;
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
id = FindUniqueIdByPath(path);
|
||||
if (id.isNull())
|
||||
return;
|
||||
|
||||
emit beginRemoveRows(QModelIndex(), index.row(), index.row());
|
||||
device_info_.removeAt(index.row());
|
||||
emit endRemoveRows();
|
||||
device_data_.remove(id);
|
||||
}
|
||||
|
||||
emit DeviceRemoved(id);
|
||||
}
|
||||
|
||||
void FilesystemDeviceEngine::DeviceChanged(const QDBusObjectPath &path) {
|
||||
QModelIndex index = FindDevice(path);
|
||||
DeviceInfo info = ReadDeviceInfo(path);
|
||||
void FilesystemDeviceEngine::DBusDeviceChanged(const QDBusObjectPath &path) {
|
||||
bool already_known = false;
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
already_known = !FindUniqueIdByPath(path).isNull();
|
||||
}
|
||||
|
||||
if (index.isValid() && !info.suitable)
|
||||
DeviceRemoved(path);
|
||||
else if (!index.isValid() && info.suitable)
|
||||
DeviceAdded(path);
|
||||
else if (index.isValid() && info.suitable) {
|
||||
device_info_[index.row()] = info;
|
||||
emit dataChanged(index, index.sibling(index.row(), columnCount()));
|
||||
DeviceData data = ReadDeviceData(path);
|
||||
|
||||
if (already_known && !data.suitable)
|
||||
DeviceRemoved(data.unique_id());
|
||||
else if (!already_known && data.suitable)
|
||||
DeviceAdded(data.unique_id());
|
||||
else if (already_known && data.suitable) {
|
||||
{
|
||||
QMutexLocker l(&mutex_);
|
||||
device_data_[data.unique_id()] = data;
|
||||
}
|
||||
emit DeviceChanged(data.unique_id());
|
||||
}
|
||||
}
|
||||
|
||||
QString FilesystemDeviceEngine::FindUniqueIdByPath(const QDBusObjectPath &path) const {
|
||||
foreach (const DeviceData& data, device_data_) {
|
||||
if (data.dbus_path == path.path())
|
||||
return data.unique_id();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "deviceengine.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QStringList>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
@ -31,31 +32,32 @@ class FilesystemDeviceEngine : public DeviceEngine {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FilesystemDeviceEngine(QObject *parent = 0);
|
||||
FilesystemDeviceEngine();
|
||||
~FilesystemDeviceEngine();
|
||||
|
||||
enum Column {
|
||||
Column_MountPath = LastDeviceEngineColumn,
|
||||
Column_DbusPath,
|
||||
enum Field {
|
||||
Field_MountPath = LastDeviceEngineField,
|
||||
Field_DbusPath,
|
||||
|
||||
LastFilesystemDeviceEngineColumn
|
||||
LastFilesystemDeviceEngineField
|
||||
};
|
||||
|
||||
bool Init();
|
||||
QStringList DeviceUniqueIDs();
|
||||
QVariant DeviceInfo(const QString& id, int field);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
protected:
|
||||
void Init();
|
||||
|
||||
private slots:
|
||||
void DeviceAdded(const QDBusObjectPath& path);
|
||||
void DeviceRemoved(const QDBusObjectPath& path);
|
||||
void DeviceChanged(const QDBusObjectPath& path);
|
||||
void DBusDeviceAdded(const QDBusObjectPath& path);
|
||||
void DBusDeviceRemoved(const QDBusObjectPath& path);
|
||||
void DBusDeviceChanged(const QDBusObjectPath& path);
|
||||
|
||||
private:
|
||||
struct DeviceInfo {
|
||||
DeviceInfo() : suitable(false), device_size(0) {}
|
||||
struct DeviceData {
|
||||
DeviceData() : suitable(false), device_size(0) {}
|
||||
|
||||
QString unique_id() const;
|
||||
|
||||
bool suitable;
|
||||
QString dbus_path;
|
||||
|
@ -66,19 +68,18 @@ private:
|
|||
QString device_presentation_icon_name;
|
||||
QStringList device_mount_paths;
|
||||
quint64 device_size;
|
||||
|
||||
QString unique_id() const;
|
||||
};
|
||||
|
||||
void Reset();
|
||||
DeviceInfo ReadDeviceInfo(const QDBusObjectPath& path) const;
|
||||
DeviceData ReadDeviceData(const QDBusObjectPath& path) const;
|
||||
|
||||
QModelIndex FindDevice(const QDBusObjectPath& path) const;
|
||||
// You MUST hold the mutex while calling this function
|
||||
QString FindUniqueIdByPath(const QDBusObjectPath& path) const;
|
||||
|
||||
private:
|
||||
boost::scoped_ptr<OrgFreedesktopUDisksInterface> interface_;
|
||||
|
||||
QList<DeviceInfo> device_info_;
|
||||
QMutex mutex_;
|
||||
QMap<QString, DeviceData> device_data_;
|
||||
};
|
||||
|
||||
#endif // FILESYSTEMDEVICEENGINE_H
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "ui/iconloader.h"
|
||||
#include "ui/mainwindow.h"
|
||||
|
||||
#include "devices/devicetest.h" // TODO: Remove me
|
||||
|
||||
#include <QtSingleApplication>
|
||||
#include <QtDebug>
|
||||
#include <QLibraryInfo>
|
||||
|
@ -164,6 +166,8 @@ int main(int argc, char *argv[]) {
|
|||
MPRIS mpris;
|
||||
#endif
|
||||
|
||||
DeviceTest device_test; // TODO: Remove me (and the header)
|
||||
|
||||
// Window
|
||||
MainWindow w(&network, options.engine());
|
||||
|
||||
|
|
Loading…
Reference in New Issue