mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
feat: refactor to use UxPlay
This commit is contained in:
+3
-3
@@ -1,6 +1,6 @@
|
||||
[submodule "lib/airplay"]
|
||||
path = lib/airplay
|
||||
url = https://github.com/uncor3/airplay
|
||||
[submodule "lib/uxplay"]
|
||||
path = lib/uxplay
|
||||
url = https://github.com/iDescriptor/uxplay
|
||||
[submodule "lib/ipatool-go"]
|
||||
path = lib/ipatool-go
|
||||
url = https://github.com/uncor3/libipatool-go.git
|
||||
|
||||
+5
-3
@@ -217,7 +217,7 @@ if (NOT ENABLE_RECOVERY_DEVICE_SUPPORT)
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(lib/airplay)
|
||||
add_subdirectory(lib/uxplay)
|
||||
add_subdirectory(lib/ipatool-go)
|
||||
add_subdirectory(lib/zupdater)
|
||||
|
||||
@@ -283,7 +283,7 @@ target_link_libraries(iDescriptor PRIVATE
|
||||
PkgConfig::AVCODEC
|
||||
PkgConfig::AVUTIL
|
||||
PkgConfig::SWSCALE
|
||||
airplay
|
||||
uxplay
|
||||
ipatool-go
|
||||
ZUpdater
|
||||
)
|
||||
@@ -294,7 +294,9 @@ if(ENABLE_RECOVERY_DEVICE_SUPPORT)
|
||||
endif()
|
||||
|
||||
target_include_directories(iDescriptor PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/zupdater/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/zupdater/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
|
||||
-1
Submodule lib/airplay deleted from 9fe5788667
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/uncore/Desktop/clones/UxPlay
|
||||
+172
-44
@@ -21,9 +21,14 @@
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMediaPlayer>
|
||||
@@ -31,10 +36,11 @@
|
||||
#include <QPalette>
|
||||
#include <QPixmap>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QVideoWidget>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// V4L2 includes
|
||||
#include <cstring>
|
||||
@@ -44,12 +50,63 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "settingsmanager.h"
|
||||
|
||||
// Include the rpiplay server functions
|
||||
#include "../lib/airplay/renderers/video_renderer.h"
|
||||
extern "C" {
|
||||
int start_server_qt(const char *name, void *callbacks);
|
||||
int stop_server_qt();
|
||||
#include <uxplay/renderers/video_renderer.h>
|
||||
#include <uxplay/uxplay.h>
|
||||
|
||||
AirPlaySettings::AirPlaySettings()
|
||||
: fps(SettingsManager::sharedInstance()->airplayFps())
|
||||
{
|
||||
}
|
||||
|
||||
QStringList AirPlaySettings::toArgs() const
|
||||
{
|
||||
QStringList args;
|
||||
|
||||
// FPS
|
||||
args << "-fps" << QString::number(fps);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
AirPlaySettingsDialog::AirPlaySettingsDialog(QWidget *parent)
|
||||
: QDialog(parent), m_settings(AirPlaySettings())
|
||||
{
|
||||
setupUI();
|
||||
setWindowTitle("AirPlay Settings");
|
||||
resize(500, 600);
|
||||
}
|
||||
|
||||
void AirPlaySettingsDialog::setupUI()
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// Video Settings Group
|
||||
QGroupBox *videoGroup = new QGroupBox("Video Settings");
|
||||
QFormLayout *videoLayout = new QFormLayout(videoGroup);
|
||||
|
||||
m_fpsSpinBox = new QSpinBox();
|
||||
m_fpsSpinBox->setRange(1, 255);
|
||||
m_fpsSpinBox->setValue(SettingsManager::sharedInstance()->airplayFps());
|
||||
m_fpsSpinBox->setToolTip("Set maximum allowed streaming framerate");
|
||||
videoLayout->addRow("Max FPS:", m_fpsSpinBox);
|
||||
|
||||
mainLayout->addWidget(videoGroup);
|
||||
|
||||
// Buttons
|
||||
QDialogButtonBox *buttonBox =
|
||||
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
AirPlaySettings AirPlaySettingsDialog::getSettings() const
|
||||
{
|
||||
AirPlaySettings settings;
|
||||
settings.fps = m_fpsSpinBox->value();
|
||||
return settings;
|
||||
}
|
||||
|
||||
AirPlayWindow::AirPlayWindow(QWidget *parent)
|
||||
@@ -57,16 +114,15 @@ AirPlayWindow::AirPlayWindow(QWidget *parent)
|
||||
m_streamingWidget(nullptr), m_loadingIndicator(nullptr),
|
||||
m_loadingLabel(nullptr), m_tutorialPlayer(nullptr),
|
||||
m_tutorialVideoWidget(nullptr), m_videoLabel(nullptr),
|
||||
m_tutorialLayout(nullptr), m_v4l2Checkbox(nullptr),
|
||||
m_serverThread(nullptr), m_serverRunning(false)
|
||||
#ifdef Q_OS_LINUX
|
||||
,
|
||||
m_v4l2_fd(-1), m_v4l2_width(0), m_v4l2_height(0), m_v4l2_enabled(false)
|
||||
m_tutorialLayout(nullptr), m_settingsButton(nullptr),
|
||||
#ifdef __linux__
|
||||
m_v4l2Checkbox(nullptr), m_v4l2_fd(-1), m_v4l2_width(0), m_v4l2_height(0),
|
||||
m_v4l2_enabled(false),
|
||||
#endif
|
||||
m_serverThread(nullptr), m_serverRunning(false), m_clientConnected(false)
|
||||
{
|
||||
setupUI();
|
||||
|
||||
// Auto-start server after UI setup
|
||||
QTimer::singleShot(500, this, &AirPlayWindow::startAirPlayServer);
|
||||
}
|
||||
|
||||
@@ -109,6 +165,17 @@ void AirPlayWindow::setupUI()
|
||||
m_tutorialLayout->addLayout(loadingLayout);
|
||||
m_tutorialLayout->addSpacing(1);
|
||||
|
||||
// Settings button (shown when no client connected)
|
||||
m_settingsButton = new QPushButton("Settings");
|
||||
m_settingsButton->setVisible(false);
|
||||
connect(m_settingsButton, &QPushButton::clicked, this,
|
||||
&AirPlayWindow::showSettingsDialog);
|
||||
QHBoxLayout *settingsLayout = new QHBoxLayout();
|
||||
settingsLayout->addStretch();
|
||||
settingsLayout->addWidget(m_settingsButton);
|
||||
settingsLayout->addStretch();
|
||||
m_tutorialLayout->addLayout(settingsLayout);
|
||||
|
||||
QTimer::singleShot(100, this, &AirPlayWindow::setupTutorialVideo);
|
||||
|
||||
m_streamingWidget = new QWidget();
|
||||
@@ -116,7 +183,7 @@ void AirPlayWindow::setupUI()
|
||||
streamingLayout->setContentsMargins(10, 10, 10, 10);
|
||||
streamingLayout->setSpacing(10);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifdef __linux__
|
||||
// Add V4L2 checkbox at the top of streaming view
|
||||
setupV4L2Checkbox();
|
||||
if (m_v4l2Checkbox) {
|
||||
@@ -193,6 +260,22 @@ void AirPlayWindow::showStreamingView()
|
||||
}
|
||||
}
|
||||
|
||||
void AirPlayWindow::showSettingsDialog()
|
||||
{
|
||||
AirPlaySettingsDialog dialog(this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
AirPlaySettings newSettings = dialog.getSettings();
|
||||
|
||||
// Save settings
|
||||
SettingsManager::sharedInstance()->setAirplayFps(newSettings.fps);
|
||||
|
||||
QMessageBox::information(this, "Settings Saved",
|
||||
"AirPlay will be restarted to apply the new "
|
||||
"settings.");
|
||||
emit restartRequested();
|
||||
}
|
||||
}
|
||||
|
||||
void AirPlayWindow::startAirPlayServer()
|
||||
{
|
||||
if (m_serverRunning)
|
||||
@@ -205,15 +288,23 @@ void AirPlayWindow::startAirPlayServer()
|
||||
&AirPlayWindow::updateVideoFrame);
|
||||
connect(m_serverThread, &AirPlayServerThread::clientConnectionChanged, this,
|
||||
&AirPlayWindow::onClientConnectionChanged);
|
||||
connect(m_serverThread, &AirPlayServerThread::errorOccurred, this,
|
||||
[this](const QString &message) {
|
||||
QMessageBox::critical(this, "AirPlay Server Error", message);
|
||||
close();
|
||||
});
|
||||
|
||||
QStringList args = m_settings.toArgs();
|
||||
m_serverThread->setArguments(args);
|
||||
m_serverThread->start();
|
||||
}
|
||||
|
||||
void AirPlayWindow::stopAirPlayServer()
|
||||
{
|
||||
if (m_serverThread) {
|
||||
m_serverThread->stopServer();
|
||||
m_serverThread->wait(3000);
|
||||
// m_serverThread->stopServer();
|
||||
// m_serverThread->wait(3000);
|
||||
m_serverThread->quit();
|
||||
m_serverThread->deleteLater();
|
||||
m_serverThread = nullptr;
|
||||
}
|
||||
@@ -223,8 +314,10 @@ void AirPlayWindow::stopAirPlayServer()
|
||||
void AirPlayWindow::updateVideoFrame(QByteArray frameData, int width,
|
||||
int height)
|
||||
{
|
||||
if (frameData.size() != width * height * 3)
|
||||
if (frameData.size() != width * height * 3) {
|
||||
qDebug() << "Invalid frame data size";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
// V4L2 output if enabled
|
||||
@@ -258,6 +351,11 @@ void AirPlayWindow::onServerStatusChanged(bool running)
|
||||
|
||||
// Show tutorial video and instructions
|
||||
m_tutorialVideoWidget->setVisible(true);
|
||||
|
||||
// Show settings button when server is running but no client connected
|
||||
m_settingsButton->setVisible(!m_clientConnected);
|
||||
|
||||
// Show tutorial video and instructions
|
||||
QLabel *instructionLabel = m_tutorialWidget->findChild<QLabel *>();
|
||||
if (instructionLabel && !instructionLabel->text().contains("Follow")) {
|
||||
// Find the instruction label (not title or loading label)
|
||||
@@ -279,6 +377,10 @@ void AirPlayWindow::onServerStatusChanged(bool running)
|
||||
void AirPlayWindow::onClientConnectionChanged(bool connected)
|
||||
{
|
||||
m_clientConnected = connected;
|
||||
|
||||
// Hide settings button when client is connected
|
||||
m_settingsButton->setVisible(!connected && m_serverRunning);
|
||||
|
||||
if (connected) {
|
||||
m_loadingLabel->setText("Device connected - receiving stream...");
|
||||
|
||||
@@ -340,57 +442,80 @@ AirPlayServerThread::AirPlayServerThread(QObject *parent)
|
||||
|
||||
AirPlayServerThread::~AirPlayServerThread()
|
||||
{
|
||||
stopServer();
|
||||
// stopServer();
|
||||
uxplay_cleanup();
|
||||
wait();
|
||||
}
|
||||
|
||||
void AirPlayServerThread::stopServer()
|
||||
void AirPlayServerThread::setArguments(const QStringList &args)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_shouldStop = true;
|
||||
m_waitCondition.wakeAll();
|
||||
|
||||
m_argData.clear();
|
||||
m_argv.clear();
|
||||
|
||||
m_argData.append("uxplay");
|
||||
|
||||
// Add all arguments
|
||||
for (const QString &arg : args) {
|
||||
m_argData.append(arg.toUtf8());
|
||||
}
|
||||
|
||||
// Build argv array with persistent pointers
|
||||
for (QByteArray &data : m_argData) {
|
||||
m_argv.append(data.data());
|
||||
}
|
||||
}
|
||||
|
||||
// Global pointer to current server thread for callbacks
|
||||
static AirPlayServerThread *g_currentServerThread = nullptr;
|
||||
|
||||
// Static callback wrappers for C interface
|
||||
extern "C" void qt_video_callback(uint8_t *data, int width, int height)
|
||||
void frame_callback(const unsigned char *data, int width, int height,
|
||||
int stride, int format)
|
||||
{
|
||||
if (g_currentServerThread) {
|
||||
QByteArray frameData((const char *)data, width * height * 3);
|
||||
emit g_currentServerThread->videoFrameReady(frameData, width, height);
|
||||
}
|
||||
if (!g_currentServerThread)
|
||||
return;
|
||||
QByteArray frameData((const char *)data, width * height * 3);
|
||||
emit g_currentServerThread->videoFrameReady(frameData, width, height);
|
||||
}
|
||||
|
||||
extern "C" void qt_connection_callback(bool connected)
|
||||
void connection_callback(bool connected)
|
||||
{
|
||||
if (g_currentServerThread) {
|
||||
emit g_currentServerThread->clientConnectionChanged(connected);
|
||||
}
|
||||
qDebug() << "Connection callback: "
|
||||
<< (connected ? "Connected" : "Disconnected");
|
||||
if (!g_currentServerThread)
|
||||
return;
|
||||
emit g_currentServerThread->clientConnectionChanged(connected);
|
||||
}
|
||||
|
||||
void AirPlayServerThread::run()
|
||||
{
|
||||
g_currentServerThread = this;
|
||||
emit statusChanged(true);
|
||||
callbacks_t callbacks;
|
||||
callbacks.frame_callback = frame_callback;
|
||||
callbacks.connection_callback = connection_callback;
|
||||
uxplay_callbacks = &callbacks;
|
||||
|
||||
// Create callbacks structure
|
||||
video_renderer_qt_callbacks_t callbacks;
|
||||
callbacks.video_callback = qt_video_callback;
|
||||
callbacks.connection_callback = qt_connection_callback;
|
||||
|
||||
start_server_qt("iDescriptor", &callbacks);
|
||||
|
||||
// Wait efficiently until stopServer() is called
|
||||
QMutexLocker locker(&m_mutex);
|
||||
while (!m_shouldStop) {
|
||||
m_waitCondition.wait(&m_mutex);
|
||||
qDebug() << "Starting AirPlay server with arguments:" << m_argv.size();
|
||||
for (int i = 0; i < m_argv.size(); ++i) {
|
||||
qDebug() << " argv[" << i << "] =" << m_argv[i];
|
||||
}
|
||||
|
||||
stop_server_qt();
|
||||
try {
|
||||
int res = init_uxplay(m_argv.size(), m_argv.data());
|
||||
qDebug() << "AirPlay server exited with code: " << res;
|
||||
if (res != 0) {
|
||||
emit errorOccurred("AirPlay server exited unexpectedly.");
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "Exception in AirPlay server thread: " << e.what();
|
||||
emit errorOccurred(
|
||||
QString("AirPlay server encountered an error: %1").arg(e.what()));
|
||||
}
|
||||
|
||||
uxplay_callbacks = nullptr;
|
||||
g_currentServerThread = nullptr;
|
||||
emit statusChanged(false);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -511,6 +636,9 @@ bool AirPlayWindow::createV4L2Loopback()
|
||||
|
||||
void AirPlayWindow::setupV4L2Checkbox()
|
||||
{
|
||||
if (!SettingsManager::sharedInstance()->showV4L2())
|
||||
return;
|
||||
|
||||
try {
|
||||
m_v4l2Checkbox = new QCheckBox("Enable V4L2 Virtual Camera Output");
|
||||
m_v4l2Checkbox->setToolTip("Enable output to virtual camera device "
|
||||
@@ -524,4 +652,4 @@ void AirPlayWindow::setupV4L2Checkbox()
|
||||
qWarning("Exception occurred while setting up V4L2 checkbox");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+63
-26
@@ -23,10 +23,18 @@
|
||||
#include "qprocessindicator.h"
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QMediaPlayer>
|
||||
#include <QMutex>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QStackedWidget>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
@@ -40,22 +48,49 @@ class AirPlayServerThread : public QThread
|
||||
|
||||
public:
|
||||
explicit AirPlayServerThread(QObject *parent = nullptr);
|
||||
~AirPlayServerThread() override;
|
||||
~AirPlayServerThread();
|
||||
|
||||
void stopServer();
|
||||
// void stopServer();
|
||||
void setArguments(const QStringList &args);
|
||||
|
||||
signals:
|
||||
void statusChanged(bool running);
|
||||
void videoFrameReady(QByteArray frameData, int width, int height);
|
||||
void clientConnectionChanged(bool connected);
|
||||
void errorOccurred(const QString &message);
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
bool m_shouldStop;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
bool m_shouldStop;
|
||||
QVector<QByteArray> m_argData;
|
||||
QVector<char *> m_argv;
|
||||
};
|
||||
|
||||
class AirPlaySettings
|
||||
{
|
||||
public:
|
||||
explicit AirPlaySettings();
|
||||
int fps;
|
||||
|
||||
QStringList toArgs() const;
|
||||
};
|
||||
|
||||
class AirPlaySettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AirPlaySettingsDialog(QWidget *parent = nullptr);
|
||||
AirPlaySettings getSettings() const;
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
||||
QSpinBox *m_fpsSpinBox;
|
||||
AirPlaySettings m_settings;
|
||||
};
|
||||
|
||||
class AirPlayWindow : public QMainWindow
|
||||
@@ -66,22 +101,34 @@ public:
|
||||
explicit AirPlayWindow(QWidget *parent = nullptr);
|
||||
~AirPlayWindow();
|
||||
|
||||
public slots:
|
||||
void updateVideoFrame(QByteArray frameData, int width, int height);
|
||||
void onClientConnectionChanged(bool connected);
|
||||
|
||||
private slots:
|
||||
void updateVideoFrame(QByteArray frameData, int width, int height);
|
||||
void onServerStatusChanged(bool running);
|
||||
void onClientConnectionChanged(bool connected);
|
||||
void showSettingsDialog();
|
||||
#ifdef __linux__
|
||||
void onV4L2CheckboxToggled(bool enabled);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void restartRequested();
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void startAirPlayServer();
|
||||
void stopAirPlayServer();
|
||||
void setupTutorialVideo();
|
||||
void showTutorialView();
|
||||
void showStreamingView();
|
||||
void startAirPlayServer();
|
||||
void stopAirPlayServer();
|
||||
|
||||
#ifdef __linux__
|
||||
void initV4L2(int width, int height, const char *device = "/dev/video0");
|
||||
void closeV4L2();
|
||||
void writeFrameToV4L2(uint8_t *data, int width, int height);
|
||||
bool checkV4L2LoopbackExists();
|
||||
bool createV4L2Loopback();
|
||||
void setupV4L2Checkbox();
|
||||
#endif
|
||||
|
||||
// UI Components
|
||||
QStackedWidget *m_stackedWidget;
|
||||
@@ -94,30 +141,20 @@ private:
|
||||
QVideoWidget *m_tutorialVideoWidget;
|
||||
QLabel *m_videoLabel;
|
||||
QVBoxLayout *m_tutorialLayout;
|
||||
QCheckBox *m_v4l2Checkbox;
|
||||
|
||||
AirPlayServerThread *m_serverThread;
|
||||
bool m_serverRunning;
|
||||
bool m_clientConnected = false;
|
||||
QPushButton *m_settingsButton;
|
||||
|
||||
#ifdef __linux__
|
||||
public:
|
||||
// V4L2 members - public for C callback access
|
||||
QCheckBox *m_v4l2Checkbox;
|
||||
int m_v4l2_fd;
|
||||
int m_v4l2_width;
|
||||
int m_v4l2_height;
|
||||
bool m_v4l2_enabled = false;
|
||||
|
||||
// V4L2 methods
|
||||
void writeFrameToV4L2(uint8_t *data, int width, int height);
|
||||
|
||||
private:
|
||||
void initV4L2(int width, int height, const char *device);
|
||||
void closeV4L2();
|
||||
bool checkV4L2LoopbackExists();
|
||||
bool createV4L2Loopback();
|
||||
void setupV4L2Checkbox();
|
||||
#endif
|
||||
|
||||
AirPlayServerThread *m_serverThread;
|
||||
bool m_serverRunning;
|
||||
bool m_clientConnected;
|
||||
AirPlaySettings m_settings;
|
||||
};
|
||||
|
||||
#endif // AIRPLAYWINDOW_H
|
||||
|
||||
+25
-1
@@ -390,4 +390,28 @@ void SettingsManager::setIconSizeBaseMultiplier(double multiplier)
|
||||
{
|
||||
m_settings->setValue("iconSizeBaseMultiplier", multiplier);
|
||||
m_settings->sync();
|
||||
}
|
||||
}
|
||||
|
||||
int SettingsManager::airplayFps() const
|
||||
{
|
||||
return m_settings->value("airplayFps", 60).toInt();
|
||||
}
|
||||
|
||||
void SettingsManager::setAirplayFps(int fps)
|
||||
{
|
||||
m_settings->setValue("airplayFps", fps);
|
||||
m_settings->sync();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
bool SettingsManager::showV4L2() const
|
||||
{
|
||||
return m_settings->value("showV4L2", false).toBool();
|
||||
}
|
||||
|
||||
void SettingsManager::setShowV4L2(bool show)
|
||||
{
|
||||
m_settings->setValue("showV4L2", show);
|
||||
m_settings->sync();
|
||||
}
|
||||
#endif
|
||||
@@ -105,6 +105,13 @@ public:
|
||||
|
||||
double iconSizeBaseMultiplier() const;
|
||||
void setIconSizeBaseMultiplier(double multiplier);
|
||||
|
||||
int airplayFps() const;
|
||||
void setAirplayFps(int fps);
|
||||
#ifdef __linux__
|
||||
bool showV4L2() const;
|
||||
void setShowV4L2(bool show);
|
||||
#endif
|
||||
signals:
|
||||
void favoritePlacesChanged();
|
||||
void recentLocationsChanged();
|
||||
|
||||
@@ -153,6 +153,30 @@ void SettingsWidget::setupUI()
|
||||
|
||||
scrollLayout->addWidget(jailbrokenGroup);
|
||||
|
||||
// === AirPlay SETTINGS ===
|
||||
auto *airplayGroup = new QGroupBox("AirPlay");
|
||||
auto *airplayLayout = new QVBoxLayout(airplayGroup);
|
||||
|
||||
auto *fpsLayout = new QHBoxLayout();
|
||||
|
||||
auto *fpsLabel = new QLabel("Fps:");
|
||||
m_airplayFpsSpinBox = new QSpinBox();
|
||||
m_airplayFpsSpinBox->setRange(1, 255);
|
||||
m_airplayFpsSpinBox->setToolTip(
|
||||
"Set the fps for AirPlay. Go with 30 fps if have an older device.");
|
||||
|
||||
fpsLayout->addWidget(fpsLabel);
|
||||
fpsLayout->addWidget(m_airplayFpsSpinBox);
|
||||
fpsLayout->addStretch();
|
||||
airplayLayout->addLayout(fpsLayout);
|
||||
|
||||
#ifdef __linux__
|
||||
m_showV4L2CheckBox = new QCheckBox("Show V4L2 Button on AirPlay Widget");
|
||||
airplayLayout->addWidget(m_showV4L2CheckBox);
|
||||
#endif
|
||||
|
||||
scrollLayout->addWidget(airplayGroup);
|
||||
|
||||
// === MISCELLANEOUS SETTINGS ===
|
||||
auto *miscGroup = new QGroupBox("Miscellaneous");
|
||||
auto *miscLayout = new QVBoxLayout(miscGroup);
|
||||
@@ -250,6 +274,10 @@ void SettingsWidget::loadSettings()
|
||||
m_applyButton->setEnabled(false);
|
||||
|
||||
m_iconSizeBaseMultiplier->setValue(sm->iconSizeBaseMultiplier());
|
||||
m_airplayFpsSpinBox->setValue(sm->airplayFps());
|
||||
#ifdef __linux__
|
||||
m_showV4L2CheckBox->setChecked(sm->showV4L2());
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsWidget::connectSignals()
|
||||
@@ -380,6 +408,10 @@ void SettingsWidget::saveSettings()
|
||||
|
||||
sm->setIconSizeBaseMultiplier(m_iconSizeBaseMultiplier->value());
|
||||
|
||||
sm->setAirplayFps(m_airplayFpsSpinBox->value());
|
||||
#ifdef __linux__
|
||||
sm->setShowV4L2(m_showV4L2CheckBox->isChecked());
|
||||
#endif
|
||||
m_applyButton->setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,13 @@ private:
|
||||
|
||||
QDoubleSpinBox *m_iconSizeBaseMultiplier;
|
||||
|
||||
// Airplay
|
||||
QSpinBox *m_airplayFpsSpinBox;
|
||||
|
||||
#ifdef __linux__
|
||||
QCheckBox *m_showV4L2CheckBox;
|
||||
#endif
|
||||
|
||||
// Buttons
|
||||
QPushButton *m_checkUpdatesButton;
|
||||
QPushButton *m_resetButton;
|
||||
|
||||
@@ -409,6 +409,17 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool)
|
||||
m_airplayWindow = new AirPlayWindow();
|
||||
connect(m_airplayWindow, &QObject::destroyed, this,
|
||||
[this]() { m_airplayWindow = nullptr; });
|
||||
connect(m_airplayWindow, &AirPlayWindow::restartRequested, this,
|
||||
[this]() {
|
||||
if (m_airplayWindow) {
|
||||
m_airplayWindow->close();
|
||||
}
|
||||
m_airplayWindow = new AirPlayWindow();
|
||||
m_airplayWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_airplayWindow->setWindowFlag(Qt::Window);
|
||||
m_airplayWindow->resize(400, 300);
|
||||
m_airplayWindow->show();
|
||||
});
|
||||
m_airplayWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_airplayWindow->setWindowFlag(Qt::Window);
|
||||
m_airplayWindow->resize(400, 300);
|
||||
|
||||
Reference in New Issue
Block a user