1
0
Fork 0

[Multiple] Moved to Slots + Signals instead of calling JS functions or manually changing object values.

This commit is contained in:
NamedKitten 2018-11-17 15:45:21 +00:00
parent 8c71f0b341
commit 5f0d602041
11 changed files with 319 additions and 167 deletions

View file

@ -27,6 +27,7 @@ set(SOURCES
src/main.cpp src/main.cpp
src/MpvPlayerBackend.cpp src/MpvPlayerBackend.cpp
src/utils.cpp src/utils.cpp
src/enums.hpp
) )
find_program(CCACHE_FOUND ccache) find_program(CCACHE_FOUND ccache)

View file

@ -16,20 +16,23 @@
#include "discord_rpc.h" #include "discord_rpc.h"
#endif #endif
namespace { namespace {
void wakeup(void* ctx) void
wakeup(void* ctx)
{ {
QMetaObject::invokeMethod((MpvPlayerBackend*)ctx, "on_mpv_events", Qt::QueuedConnection); QMetaObject::invokeMethod(
(MpvPlayerBackend*)ctx, "on_mpv_events", Qt::QueuedConnection);
} }
void on_mpv_redraw(void* ctx) void
on_mpv_redraw(void* ctx)
{ {
MpvPlayerBackend::on_update(ctx); MpvPlayerBackend::on_update(ctx);
} }
static void* get_proc_address_mpv(void* ctx, const char* name) static void*
get_proc_address_mpv(void* ctx, const char* name)
{ {
Q_UNUSED(ctx) Q_UNUSED(ctx)
@ -59,10 +62,15 @@ public:
{ {
// init mpv_gl: // init mpv_gl:
if (!obj->mpv_gl) { if (!obj->mpv_gl) {
mpv_opengl_init_params gl_init_params{ get_proc_address_mpv, nullptr, nullptr }; mpv_opengl_init_params gl_init_params{ get_proc_address_mpv,
mpv_render_param params[]{ { MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL) }, nullptr,
nullptr };
mpv_render_param params[]{
{ MPV_RENDER_PARAM_API_TYPE,
const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL) },
{ MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params }, { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params },
{ MPV_RENDER_PARAM_INVALID, nullptr } }; { MPV_RENDER_PARAM_INVALID, nullptr }
};
if (mpv_render_context_create(&obj->mpv_gl, obj->mpv, params) < 0) if (mpv_render_context_create(&obj->mpv_gl, obj->mpv, params) < 0)
throw std::runtime_error("failed to initialize mpv GL context"); throw std::runtime_error("failed to initialize mpv GL context");
mpv_render_context_set_update_callback(obj->mpv_gl, on_mpv_redraw, obj); mpv_render_context_set_update_callback(obj->mpv_gl, on_mpv_redraw, obj);
@ -77,12 +85,14 @@ public:
obj->window()->resetOpenGLState(); obj->window()->resetOpenGLState();
QOpenGLFramebufferObject* fbo = framebufferObject(); QOpenGLFramebufferObject* fbo = framebufferObject();
mpv_opengl_fbo mpfbo{ mpv_opengl_fbo mpfbo{ .fbo = static_cast<int>(fbo->handle()),
.fbo = static_cast<int>(fbo->handle()), .w = fbo->width(), .h = fbo->height(), .internal_format = 0 .w = fbo->width(),
}; .h = fbo->height(),
.internal_format = 0 };
int flip_y{ 0 }; int flip_y{ 0 };
mpv_render_param params[] = { // Specify the default framebuffer (0) as target. This will mpv_render_param params[] = {
// Specify the default framebuffer (0) as target. This will
// render onto the entire screen. If you want to show the video // render onto the entire screen. If you want to show the video
// in a smaller rectangle or apply fancy transformations, you'll // in a smaller rectangle or apply fancy transformations, you'll
// need to render into a separate FBO and draw it manually. // need to render into a separate FBO and draw it manually.
@ -106,11 +116,11 @@ MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
if (!mpv) if (!mpv)
throw std::runtime_error("could not create mpv context"); throw std::runtime_error("could not create mpv context");
#ifdef DISCORD #ifdef DISCORD
DiscordEventHandlers handlers; DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers)); memset(&handlers, 0, sizeof(handlers));
Discord_Initialize("511220330996432896", &handlers, 1, NULL); Discord_Initialize("511220330996432896", &handlers, 1, NULL);
#endif #endif
mpv_set_option_string(mpv, "terminal", "yes"); mpv_set_option_string(mpv, "terminal", "yes");
mpv_set_option_string(mpv, "msg-level", "all=v"); mpv_set_option_string(mpv, "msg-level", "all=v");
@ -130,8 +140,8 @@ MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE); mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
mpv_observe_property(mpv, 0, "audio-device-list", MPV_FORMAT_NODE); mpv_observe_property(mpv, 0, "audio-device-list", MPV_FORMAT_NODE);
mpv_observe_property(mpv, 0, "playlist-pos", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "playlist-pos", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_NONE);
mpv_observe_property(mpv, 0, "muted", MPV_FORMAT_NONE); mpv_observe_property(mpv, 0, "mute", MPV_FORMAT_NONE);
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "media-title", MPV_FORMAT_STRING); mpv_observe_property(mpv, 0, "media-title", MPV_FORMAT_STRING);
mpv_observe_property(mpv, 0, "sub-text", MPV_FORMAT_STRING); mpv_observe_property(mpv, 0, "sub-text", MPV_FORMAT_STRING);
@ -143,7 +153,17 @@ MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
if (mpv_initialize(mpv) < 0) if (mpv_initialize(mpv) < 0)
throw std::runtime_error("could not initialize mpv context"); throw std::runtime_error("could not initialize mpv context");
connect(this, &MpvPlayerBackend::onUpdate, this, &MpvPlayerBackend::doUpdate, Qt::QueuedConnection); connect(this,
&MpvPlayerBackend::onUpdate,
this,
&MpvPlayerBackend::doUpdate,
Qt::QueuedConnection);
connect(this,
&MpvPlayerBackend::positionChanged,
&MpvPlayerBackend::updateDurationString);
connect(this,
&MpvPlayerBackend::durationChanged,
&MpvPlayerBackend::updateDurationString);
} }
MpvPlayerBackend::~MpvPlayerBackend() MpvPlayerBackend::~MpvPlayerBackend()
@ -155,60 +175,73 @@ MpvPlayerBackend::~MpvPlayerBackend()
printf("MPV terminated.\n"); printf("MPV terminated.\n");
} }
void MpvPlayerBackend::on_update(void* ctx) void
MpvPlayerBackend::on_update(void* ctx)
{ {
MpvPlayerBackend* self = (MpvPlayerBackend*)ctx; MpvPlayerBackend* self = (MpvPlayerBackend*)ctx;
emit self->onUpdate(); emit self->onUpdate();
} }
void MpvPlayerBackend::doUpdate() void
MpvPlayerBackend::doUpdate()
{ {
update(); update();
} }
QVariant MpvPlayerBackend::getProperty(const QString& name) const QVariant
MpvPlayerBackend::getProperty(const QString& name) const
{ {
return mpv::qt::get_property_variant(mpv, name); return mpv::qt::get_property_variant(mpv, name);
} }
void MpvPlayerBackend::command(const QVariant& params) void
MpvPlayerBackend::command(const QVariant& params)
{ {
mpv::qt::command_variant(mpv, params); mpv::qt::command_variant(mpv, params);
} }
void MpvPlayerBackend::setProperty(const QString& name, const QVariant& value) void
MpvPlayerBackend::setProperty(const QString& name, const QVariant& value)
{ {
mpv::qt::set_property_variant(mpv, name, value); mpv::qt::set_property_variant(mpv, name, value);
} }
void MpvPlayerBackend::setOption(const QString& name, const QVariant& value) void
MpvPlayerBackend::setOption(const QString& name, const QVariant& value)
{ {
mpv::qt::set_option_variant(mpv, name, value); mpv::qt::set_option_variant(mpv, name, value);
} }
void MpvPlayerBackend::launchAboutQt() void
MpvPlayerBackend::launchAboutQt()
{ {
QApplication* qapp = qobject_cast<QApplication*>(QCoreApplication::instance()); QApplication* qapp =
qobject_cast<QApplication*>(QCoreApplication::instance());
qapp->aboutQt(); qapp->aboutQt();
} }
#ifdef DISCORD #ifdef DISCORD
void MpvPlayerBackend::updateDiscord() void
MpvPlayerBackend::updateDiscord()
{ {
char buffer[256]; char buffer[256];
DiscordRichPresence discordPresence; DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence)); memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing"; discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
sprintf(buffer, "Currently Playing: Video %s", getProperty("media-title").toString().toUtf8().constData()); sprintf(buffer,
"Currently Playing: Video %s",
getProperty("media-title").toString().toUtf8().constData());
discordPresence.details = buffer; discordPresence.details = buffer;
discordPresence.startTimestamp = time(0); discordPresence.startTimestamp = time(0);
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() - getProperty("time-pos").toFloat()); discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
getProperty("time-pos").toFloat());
discordPresence.instance = 0; discordPresence.instance = 0;
Discord_UpdatePresence(&discordPresence); Discord_UpdatePresence(&discordPresence);
} }
#endif #endif
QVariant MpvPlayerBackend::getaudioDevices() const QVariant
MpvPlayerBackend::getaudioDevices() const
{ {
QVariant drivers = getProperty("audio-device-list"); QVariant drivers = getProperty("audio-device-list");
QVariant currentDevice = getProperty("audio-device"); QVariant currentDevice = getProperty("audio-device");
@ -229,99 +262,117 @@ QVariant MpvPlayerBackend::getaudioDevices() const
return QVariant(newDrivers); return QVariant(newDrivers);
} }
void MpvPlayerBackend::setAudioDevice(const QString& name) void
MpvPlayerBackend::setAudioDevice(const QString& name)
{ {
setProperty("audio-device", name); setProperty("audio-device", name);
} }
void MpvPlayerBackend::togglePlayPause() void
MpvPlayerBackend::togglePlayPause()
{ {
command(QVariantList() << "cycle" command(QVariantList() << "cycle"
<< "pause"); << "pause");
} }
void MpvPlayerBackend::toggleMute() void
MpvPlayerBackend::toggleMute()
{ {
command(QVariantList() << "cycle" command(QVariantList() << "cycle"
<< "mute"); << "mute");
} }
void MpvPlayerBackend::nextAudioTrack() void
MpvPlayerBackend::nextAudioTrack()
{ {
command(QVariantList() << "cycle" command(QVariantList() << "cycle"
<< "audio"); << "audio");
} }
void MpvPlayerBackend::nextSubtitleTrack() void
MpvPlayerBackend::nextSubtitleTrack()
{ {
command(QVariantList() << "cycle" command(QVariantList() << "cycle"
<< "sub"); << "sub");
} }
void MpvPlayerBackend::nextVideoTrack() void
MpvPlayerBackend::nextVideoTrack()
{ {
command(QVariantList() << "cycle" command(QVariantList() << "cycle"
<< "video"); << "video");
} }
void MpvPlayerBackend::prevPlaylistItem() void
MpvPlayerBackend::prevPlaylistItem()
{ {
command(QVariantList() << "playlist-prev"); command(QVariantList() << "playlist-prev");
} }
void MpvPlayerBackend::nextPlaylistItem() void
MpvPlayerBackend::nextPlaylistItem()
{ {
command(QVariantList() << "playlist-next" command(QVariantList() << "playlist-next"
<< "force"); << "force");
} }
void MpvPlayerBackend::loadFile(const QVariant& filename) void
MpvPlayerBackend::loadFile(const QVariant& filename)
{ {
command(QVariantList() << "loadfile" << filename); command(QVariantList() << "loadfile" << filename);
} }
void MpvPlayerBackend::appendFile(const QVariant& filename) void
MpvPlayerBackend::appendFile(const QVariant& filename)
{ {
command(QVariantList() << "loadfile" << filename << "append-play"); command(QVariantList() << "loadfile" << filename << "append-play");
} }
void MpvPlayerBackend::setVolume(const QVariant& volume) void
MpvPlayerBackend::setVolume(const QVariant& volume)
{ {
command(QVariantList() << "set" command(QVariantList() << "set"
<< "volume" << volume); << "volume" << volume);
} }
void MpvPlayerBackend::addVolume(const QVariant& volume) void
MpvPlayerBackend::addVolume(const QVariant& volume)
{ {
command(QVariantList() << "add" command(QVariantList() << "add"
<< "volume" << volume); << "volume" << volume);
} }
void MpvPlayerBackend::seekAbsolute(const QVariant& seekTime) void
MpvPlayerBackend::seekAbsolute(const QVariant& seekTime)
{ {
command(QVariantList() << "seek" << seekTime << "absolute"); command(QVariantList() << "seek" << seekTime << "absolute");
} }
void MpvPlayerBackend::seek(const QVariant& seekTime) void
MpvPlayerBackend::seek(const QVariant& seekTime)
{ {
command(QVariantList() << "seek" << seekTime); command(QVariantList() << "seek" << seekTime);
} }
QVariant MpvPlayerBackend::getTracks() const QVariant
MpvPlayerBackend::getTracks() const
{ {
return mpv::qt::get_property_variant(mpv, "track-list"); return mpv::qt::get_property_variant(mpv, "track-list");
} }
void MpvPlayerBackend::setTrack(const QVariant& track, const QVariant& id) void
MpvPlayerBackend::setTrack(const QVariant& track, const QVariant& id)
{ {
command(QVariantList() << "set" << track << id); command(QVariantList() << "set" << track << id);
} }
QVariant MpvPlayerBackend::getTrack(const QString& track) QVariant
MpvPlayerBackend::getTrack(const QString& track)
{ {
return mpv::qt::get_property_variant(mpv, track); return mpv::qt::get_property_variant(mpv, track);
} }
QVariant MpvPlayerBackend::createTimestamp(const QVariant& seconds) const QVariant
MpvPlayerBackend::createTimestamp(const QVariant& seconds) const
{ {
int d = seconds.toInt(); int d = seconds.toInt();
double h = floor(d / 3600); double h = floor(d / 3600);
@ -329,50 +380,60 @@ QVariant MpvPlayerBackend::createTimestamp(const QVariant& seconds) const
double s = floor(d % 3600 % 60); double s = floor(d % 3600 % 60);
QString hour = h > 0 ? QString::number(h) + ":" : ""; QString hour = h > 0 ? QString::number(h) + ":" : "";
QString minute = QString minute = h < 1 ? QString::number(m) + ":"
h < 1 ? QString::number(m) + ":" : (m < 10 ? "0" + QString::number(m) + ":" : QString::number(m) + ":"); : (m < 10 ? "0" + QString::number(m) + ":"
: QString::number(m) + ":");
QString second = s < 10 ? "0" + QString::number(s) : QString::number(s); QString second = s < 10 ? "0" + QString::number(s) : QString::number(s);
return hour + minute + second; return hour + minute + second;
} }
void MpvPlayerBackend::toggleOnTop() void
MpvPlayerBackend::toggleOnTop()
{ {
onTop = !onTop; onTop = !onTop;
AlwaysOnTop(window()->winId(), onTop); AlwaysOnTop(window()->winId(), onTop);
} }
void MpvPlayerBackend::toggleStats() void
MpvPlayerBackend::toggleStats()
{ {
command(QVariantList() << "script-binding" command(QVariantList() << "script-binding"
<< "stats/display-stats-toggle"); << "stats/display-stats-toggle");
} }
void MpvPlayerBackend::addSpeed(const QVariant& speed) void
MpvPlayerBackend::addSpeed(const QVariant& speed)
{ {
QString speedString = QString::number(getProperty("speed").toDouble() + speed.toDouble()); QString speedString =
QString::number(getProperty("speed").toDouble() + speed.toDouble());
speedString = speedString.left(speedString.lastIndexOf('.') + 2); speedString = speedString.left(speedString.lastIndexOf('.') + 2);
setSpeed(QVariant(speedString)); setSpeed(QVariant(speedString));
} }
void MpvPlayerBackend::subtractSpeed(const QVariant& speed) void
MpvPlayerBackend::subtractSpeed(const QVariant& speed)
{ {
QString speedString = QString::number(getProperty("speed").toDouble() - speed.toDouble()); QString speedString =
QString::number(getProperty("speed").toDouble() - speed.toDouble());
speedString = speedString.left(speedString.lastIndexOf('.') + 2); speedString = speedString.left(speedString.lastIndexOf('.') + 2);
setSpeed(QVariant(speedString)); setSpeed(QVariant(speedString));
} }
void MpvPlayerBackend::changeSpeed(const QVariant& speedFactor) void
MpvPlayerBackend::changeSpeed(const QVariant& speedFactor)
{ {
setSpeed(QVariant(getProperty("speed").toDouble() * speedFactor.toDouble())); setSpeed(QVariant(getProperty("speed").toDouble() * speedFactor.toDouble()));
} }
void MpvPlayerBackend::setSpeed(const QVariant& speed) void
MpvPlayerBackend::setSpeed(const QVariant& speed)
{ {
command(QVariantList() << "set" command(QVariantList() << "set"
<< "speed" << speed.toString()); << "speed" << speed.toString());
} }
void MpvPlayerBackend::on_mpv_events() void
MpvPlayerBackend::on_mpv_events()
{ {
while (mpv) { while (mpv) {
mpv_event* event = mpv_wait_event(mpv, 0); mpv_event* event = mpv_wait_event(mpv, 0);
@ -383,48 +444,18 @@ void MpvPlayerBackend::on_mpv_events()
} }
} }
void MpvPlayerBackend::updateDurationStringText() void
MpvPlayerBackend::updateDurationString()
{ {
findChild<QObject*>("timeLabel") emit durationStringChanged(
->setProperty("text",
QString("%1 / %2 (%3x)") QString("%1 / %2 (%3x)")
.arg(createTimestamp(getProperty("time-pos")).toString(), .arg(createTimestamp(getProperty("time-pos")).toString(),
createTimestamp(getProperty("duration")).toString(), createTimestamp(getProperty("duration")).toString(),
getProperty("speed").toString())); getProperty("speed").toString()));
} }
void MpvPlayerBackend::updatePrev(const QVariant& val) void
{ MpvPlayerBackend::handle_mpv_event(mpv_event* event)
if (val.toDouble() != 0) {
findChild<QObject*>("playlistPrevButton")->setProperty("visible", true);
} else {
findChild<QObject*>("playlistPrevButton")->setProperty("visible", false);
}
}
void MpvPlayerBackend::updateVolume(const QVariant& val)
{
if (getProperty("mute").toBool() || (val.toDouble() == 0)) {
findChild<QObject*>("volumeButton")->setProperty("iconSource", "qrc:/player/icons/volume-mute.svg");
} else {
if (val.toDouble() < 25) {
findChild<QObject*>("volumeButton")->setProperty("iconSource", "qrc:/player/icons/volume-down.svg");
} else {
findChild<QObject*>("volumeButton")->setProperty("iconSource", "qrc:/player/icons/volume-up.svg");
}
}
}
void MpvPlayerBackend::updatePlayPause(const QVariant& val)
{
if (val.toBool()) {
findChild<QObject*>("playPauseButton")->setProperty("iconSource", "qrc:/player/icons/play.svg");
} else {
findChild<QObject*>("playPauseButton")->setProperty("iconSource", "qrc:/player/icons/pause.svg");
}
}
void MpvPlayerBackend::handle_mpv_event(mpv_event* event)
{ {
switch (event->event_id) { switch (event->event_id) {
case MPV_EVENT_PROPERTY_CHANGE: { case MPV_EVENT_PROPERTY_CHANGE: {
@ -432,56 +463,61 @@ void MpvPlayerBackend::handle_mpv_event(mpv_event* event)
if (strcmp(prop->name, "time-pos") == 0) { if (strcmp(prop->name, "time-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) { if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double*)prop->data; double time = *(double*)prop->data;
updateDurationStringText(); emit positionChanged(time);
findChild<QObject*>("progressBar")->setProperty("value", time);
} }
} else if (strcmp(prop->name, "duration") == 0) { } else if (strcmp(prop->name, "duration") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) { if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double*)prop->data; double time = *(double*)prop->data;
updateDurationStringText(); emit durationChanged(time);
findChild<QObject*>("progressBar")->setProperty("to", time);
} }
} else if (strcmp(prop->name, "volume") == 0) { } else if (strcmp(prop->name, "mute") == 0 ||
if (prop->format == MPV_FORMAT_DOUBLE) { strcmp(prop->name, "volume") == 0) {
double volume = *(double*)prop->data; double volume = getProperty("volume").toDouble();
updateVolume(QVariant(volume)); bool mute = getProperty("mute").toBool();
if (mute || volume == 0) {
emit volumeStatusChanged(Enums::VolumeStatus::Muted);
} else {
if (volume < 25) {
emit volumeStatusChanged(Enums::VolumeStatus::Low);
} else {
emit volumeStatusChanged(Enums::VolumeStatus::Normal);
} }
} else if (strcmp(prop->name, "muted") == 0) { }
updateVolume(getProperty("volume")); // emit volumeChanged(volume);
} else if (strcmp(prop->name, "media-title") == 0) { } else if (strcmp(prop->name, "media-title") == 0) {
if (prop->format == MPV_FORMAT_STRING) { if (prop->format == MPV_FORMAT_STRING) {
char* title = *(char**)prop->data; char* title = *(char**)prop->data;
findChild<QObject*>("titleLabel")->setProperty("text", title); emit titleChanged(QString(title));
#ifdef DISCORD
updateDiscord();
#endif
} }
} else if (strcmp(prop->name, "sub-text") == 0) { } else if (strcmp(prop->name, "sub-text") == 0) {
if (prop->format == MPV_FORMAT_STRING) { if (prop->format == MPV_FORMAT_STRING) {
char* subs = *(char**)prop->data; char* subs = *(char**)prop->data;
findChild<QObject*>("nativeSubs")->setProperty("text", subs); emit subtitlesChanged(QString(subs));
} }
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) { } else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) { if (prop->format == MPV_FORMAT_DOUBLE) {
double duration = *(double*)prop->data; double duration = *(double*)prop->data;
QMetaObject::invokeMethod(findChild<QObject*>("progressBar"), "setCachedDuration", Q_ARG(QVariant, duration)); emit cachedDurationChanged(duration);
} }
} else if (strcmp(prop->name, "playlist-pos") == 0) { } else if (strcmp(prop->name, "playlist-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) { if (prop->format == MPV_FORMAT_DOUBLE) {
double pos = *(double*)prop->data; double pos = *(double*)prop->data;
updatePrev(QVariant(pos)); emit playlistPositionChanged(pos);
} }
} else if (strcmp(prop->name, "pause") == 0) { } else if (strcmp(prop->name, "pause") == 0) {
qDebug() << prop->data; if (getProperty("pause").toBool()) {
updatePlayPause(getProperty("pause")); emit playStatusChanged(Enums::PlayStatus::Paused);
#ifdef DISCORD } else {
updateDiscord(); emit playStatusChanged(Enums::PlayStatus::Playing);
#endif
} else if (strcmp(prop->name, "tracks-menu") == 0) {
QMetaObject::invokeMethod(findChild<QObject*>("menuBar"), "updateTracks");
} else if (strcmp(prop->name, "audio-device-list") == 0) {
QMetaObject::invokeMethod(findChild<QObject*>("audioDeviceMenu"), "update");
} }
} else if (strcmp(prop->name, "tracks-menu") == 0) {
emit tracksChanged();
} else if (strcmp(prop->name, "audio-device-list") == 0) {
emit audioDevicesChanged();
}
#ifdef DISCORD
updateDiscord();
#endif
break; break;
} }
case MPV_EVENT_SHUTDOWN: { case MPV_EVENT_SHUTDOWN: {
@ -494,7 +530,8 @@ void MpvPlayerBackend::handle_mpv_event(mpv_event* event)
} }
} }
QQuickFramebufferObject::Renderer* MpvPlayerBackend::createRenderer() const QQuickFramebufferObject::Renderer*
MpvPlayerBackend::createRenderer() const
{ {
window()->setPersistentOpenGLContext(true); window()->setPersistentOpenGLContext(true);
window()->setPersistentSceneGraph(true); window()->setPersistentSceneGraph(true);

View file

@ -9,6 +9,8 @@
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
#include "enums.hpp"
class MpvRenderer; class MpvRenderer;
class MpvPlayerBackend : public QQuickFramebufferObject class MpvPlayerBackend : public QQuickFramebufferObject
@ -41,13 +43,9 @@ public slots:
void nextPlaylistItem(); void nextPlaylistItem();
void toggleOnTop(); void toggleOnTop();
void toggleStats(); void toggleStats();
void updateDurationStringText();
QVariant getTracks() const; QVariant getTracks() const;
QVariant getaudioDevices() const; QVariant getaudioDevices() const;
void setAudioDevice(const QString& name); void setAudioDevice(const QString& name);
void updatePrev(const QVariant& val);
void updateVolume(const QVariant& val);
void updatePlayPause(const QVariant& val);
void addSpeed(const QVariant& speed); void addSpeed(const QVariant& speed);
void subtractSpeed(const QVariant& speed); void subtractSpeed(const QVariant& speed);
void changeSpeed(const QVariant& speedFactor); void changeSpeed(const QVariant& speedFactor);
@ -68,12 +66,24 @@ public slots:
signals: signals:
void onUpdate(); void onUpdate();
void positionChanged(int value);
void mpv_events(); void mpv_events();
void playStatusChanged(const Enums::PlayStatus& status);
void volumeStatusChanged(const Enums::VolumeStatus& status);
void volumeChanged(const int& volume);
void durationChanged(const double& duration);
void positionChanged(const double& position);
void cachedDurationChanged(const double& duration);
void playlistPositionChanged(const double& position);
void titleChanged(const QString& title);
void subtitlesChanged(const QString& subtitles);
void durationStringChanged(const QString& string);
void tracksChanged();
void audioDevicesChanged();
private slots: private slots:
void doUpdate(); void doUpdate();
void on_mpv_events(); void on_mpv_events();
void updateDurationString();
private: private:
void handle_mpv_event(mpv_event* event); void handle_mpv_event(mpv_event* event);

24
src/enums.hpp Normal file
View file

@ -0,0 +1,24 @@
#ifndef ENUMS_HPP
#define ENUMS_HPP
#include <QObject>
#include <QtGlobal>
namespace Enums {
Q_NAMESPACE
enum class PlayStatus : int
{
Playing = 0,
Paused = 1
};
Q_ENUM_NS(PlayStatus)
enum class VolumeStatus : int
{
Muted = 0,
Low = 1,
Normal = 2
};
Q_ENUM_NS(VolumeStatus)
}
#endif

View file

@ -6,6 +6,7 @@
#include "utils.hpp" #include "utils.hpp"
#include <cstdlib> #include <cstdlib>
#include "enums.hpp"
#include <QApplication> #include <QApplication>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
@ -110,6 +111,18 @@ main(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_NativeWindows); QApplication::setAttribute(Qt::AA_NativeWindows);
qmlRegisterUncreatableMetaObject(
Enums::staticMetaObject, // static meta object
"player", // import statement (can be any string)
1,
0, // major and minor version of the import
"Enums", // name in QML (does not have to match C++ name)
"Error: only enums" // error in case someone tries to create a MyNamespace
// object
);
qRegisterMetaType<Enums::PlayStatus>("Enums.PlayStatus");
qRegisterMetaType<Enums::VolumeStatus>("Enums.VolumeStatus");
qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend"); qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend");
std::setlocale(LC_NUMERIC, "C"); std::setlocale(LC_NUMERIC, "C");

View file

@ -69,6 +69,11 @@ Item {
width: subsContainer.childrenRect.width width: subsContainer.childrenRect.width
height: subsContainer.childrenRect.height height: subsContainer.childrenRect.height
} }
Component.onCompleted: {
player.subtitlesChanged.connect(function(subtitles) {
text = subtitles
})
}
} }
} }
} }
@ -111,12 +116,18 @@ Item {
anchors.bottomMargin: 0 anchors.bottomMargin: 0
anchors.topMargin: progressBackground.height anchors.topMargin: progressBackground.height
bottomPadding: 0 bottomPadding: 0
Component.onCompleted: {
function setCachedDuration(val) { player.positionChanged.connect(function(position) {
if (! pressed) {progressBar.value = position}
})
player.durationChanged.connect(function(duration) {
progressBar.to = duration
})
player.cachedDurationChanged.connect(function(duration) {
cachedLength.width = ((progressBar.width / progressBar.to) cachedLength.width = ((progressBar.width / progressBar.to)
* val) - progressLength.width * duration) - progressLength.width
})
} }
onMoved: { onMoved: {
player.seekAbsolute(progressBar.value) player.seekAbsolute(progressBar.value)
} }
@ -208,7 +219,6 @@ Item {
Button { Button {
id: playlistPrevButton id: playlistPrevButton
objectName: "playlistPrevButton" objectName: "playlistPrevButton"
//icon.name: "prev"
icon.source: "icons/prev.svg" icon.source: "icons/prev.svg"
icon.color: "white" icon.color: "white"
display: AbstractButton.IconOnly display: AbstractButton.IconOnly
@ -222,14 +232,20 @@ Item {
background: Rectangle { background: Rectangle {
color: "transparent" color: "transparent"
} }
Component.onCompleted: {
player.playlistPositionChanged.connect(function(position) {
if (position != 0 ) {
visible = true
} else {
visible = false
}
})
}
} }
Button { Button {
id: playPauseButton id: playPauseButton
//icon.name: "pause" icon.source: "icons/pause.svg"
objectName: "playPauseButton"
property string iconSource: "icons/pause.svg"
icon.source: iconSource
icon.color: "white" icon.color: "white"
display: AbstractButton.IconOnly display: AbstractButton.IconOnly
anchors.top: parent.top anchors.top: parent.top
@ -241,6 +257,15 @@ Item {
background: Rectangle { background: Rectangle {
color: "transparent" color: "transparent"
} }
Component.onCompleted: {
player.playStatusChanged.connect(function(status) {
if (status == Enums.PlayStatus.Playing) {
icon.source = "qrc:/player/icons/pause.svg"
} else if (status == Enums.PlayStatus.Paused) {
icon.source = "qrc:/player/icons/play.svg"
}
})
}
} }
Button { Button {
@ -263,8 +288,7 @@ Item {
Button { Button {
id: volumeButton id: volumeButton
objectName: "volumeButton" objectName: "volumeButton"
property string iconSource: "icons/volume-up.svg" icon.source: "icons/volume-up.svg"
icon.source: iconSource
icon.color: "white" icon.color: "white"
display: AbstractButton.IconOnly display: AbstractButton.IconOnly
anchors.top: parent.top anchors.top: parent.top
@ -272,11 +296,21 @@ Item {
anchors.left: playlistNextButton.right anchors.left: playlistNextButton.right
onClicked: { onClicked: {
player.toggleMute() player.toggleMute()
player.updateVolume(player.getProperty("volume"))
} }
background: Rectangle { background: Rectangle {
color: "transparent" color: "transparent"
} }
Component.onCompleted: {
player.volumeStatusChanged.connect(function(status) {
if (status == Enums.VolumeStatus.Muted) {
volumeButton.icon.source = "qrc:/player/icons/volume-mute.svg"
} else if (status == Enums.VolumeStatus.Low) {
volumeButton.icon.source = "qrc:/player/icons/volume-down.svg"
} else if (status == Enums.VolumeStatus.Normal) {
volumeButton.icon.source = "qrc:/player/icons/volume-up.svg"
}
})
}
} }
Slider { Slider {
id: volumeBar id: volumeBar
@ -299,7 +333,11 @@ Item {
onMoved: { onMoved: {
player.setVolume(Math.round(volumeBar.value).toString()) player.setVolume(Math.round(volumeBar.value).toString())
} }
Component.onCompleted: {
player.volumeChanged.connect(function(volume) {
volumeBar.value = volume
})
}
handle: Rectangle { handle: Rectangle {
x: volumeBar.leftPadding + volumeBar.visualPosition x: volumeBar.leftPadding + volumeBar.visualPosition
* (volumeBar.availableWidth - width) * (volumeBar.availableWidth - width)
@ -340,6 +378,11 @@ Item {
font.pixelSize: 14 font.pixelSize: 14
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering renderType: Text.NativeRendering
Component.onCompleted: {
player.durationStringChanged.connect(function(durationString) {
text = durationString
})
}
} }
Button { Button {

View file

@ -20,7 +20,10 @@ MenuBar {
|| subsMenuBarItem.opened || subsMenuBarItem.opened
|| aboutMenuBarItem.opened || aboutMenuBarItem.opened
objectName: "menuBar" Component.onCompleted: {
player.tracksChanged.connect(updateTracks)
}
function updateTracks() { function updateTracks() {
for (var i = 0, len = audioMenu.count; i < len; i++) { for (var i = 0, len = audioMenu.count; i < len; i++) {
@ -30,7 +33,7 @@ MenuBar {
} }
} }
for (var i = 0, len = videoMenu.count; i < len; i++) { for (var i = 0, len = videoMenu.count; i < len; i++) {
var videoAction = audioMenu.actionAt(i) var videoAction = videoMenu.actionAt(i)
if (videoAction.trackID != "no") { if (videoAction.trackID != "no") {
videoMenu.removeAction(videoAction) videoMenu.removeAction(videoAction)
} }
@ -340,7 +343,10 @@ MenuBar {
id: audioDeviceMenu id: audioDeviceMenu
objectName: "audioDeviceMenu" objectName: "audioDeviceMenu"
function update() { Component.onCompleted: {
player.audioDevicesChanged.connect(updateAudioDevices)
}
function updateAudioDevices() {
var audioDevices = player.getaudioDevices() var audioDevices = player.getaudioDevices()
for (var i = 0, len = audioDeviceMenu.count; i < len; i++) { for (var i = 0, len = audioDeviceMenu.count; i < len; i++) {

View file

@ -305,6 +305,11 @@ ApplicationWindow {
font.pixelSize: 14 font.pixelSize: 14
font.bold: true font.bold: true
opacity: 1 opacity: 1
Component.onCompleted: {
player.titleChanged.connect(function(title) {
text = title
})
}
} }
} }

View file

@ -36,7 +36,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
int setenv(const char* var, const char* value, int overwrite) int
setenv(const char* var, const char* value, int overwrite)
{ {
/* Core implementation for both setenv() and unsetenv() functions; /* Core implementation for both setenv() and unsetenv() functions;
* at the outset, assume that the requested operation may fail. * at the outset, assume that the requested operation may fail.

View file

@ -4,9 +4,11 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QtCore> #include <QtCore>
QString getPlatformName() QString
getPlatformName()
{ {
QGuiApplication* qapp = qobject_cast<QGuiApplication*>(QCoreApplication::instance()); QGuiApplication* qapp =
qobject_cast<QGuiApplication*>(QCoreApplication::instance());
return qapp->platformName(); return qapp->platformName();
} }
@ -18,7 +20,8 @@ QString getPlatformName()
#include <X11/extensions/dpms.h> #include <X11/extensions/dpms.h>
#include <X11/keysym.h> #include <X11/keysym.h>
void SetDPMS(bool on) void
SetDPMS(bool on)
{ {
qDebug() << getPlatformName(); qDebug() << getPlatformName();
if (getPlatformName() != "xcb") { if (getPlatformName() != "xcb") {
@ -34,7 +37,8 @@ void SetDPMS(bool on)
} }
} }
void AlwaysOnTop(WId wid, bool on) void
AlwaysOnTop(WId wid, bool on)
{ {
qDebug() << "On Top:" << on; qDebug() << "On Top:" << on;
Display* display = QX11Info::display(); Display* display = QX11Info::display();
@ -53,17 +57,23 @@ void AlwaysOnTop(WId wid, bool on)
event.xclient.data.l[3] = 0; event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0; event.xclient.data.l[4] = 0;
XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event); XSendEvent(display,
DefaultRootWindow(display),
False,
SubstructureRedirectMask | SubstructureNotifyMask,
&event);
} }
#else #else
void AlwaysOnTop(WId wid, bool on) void
AlwaysOnTop(WId wid, bool on)
{ {
qDebug() << "Can't set on top for platform: " << getPlatformName(); qDebug() << "Can't set on top for platform: " << getPlatformName();
} }
void SetDPMS(bool on) void
SetDPMS(bool on)
{ {
qDebug() << "Can't set DPMS for platform: " << getPlatformName(); qDebug() << "Can't set DPMS for platform: " << getPlatformName();
} }

View file

@ -3,7 +3,9 @@
#include <QWindow> #include <QWindow>
#include <stdbool.h> #include <stdbool.h>
void SetDPMS(bool on); void
void AlwaysOnTop(WId wid, bool on); SetDPMS(bool on);
void
AlwaysOnTop(WId wid, bool on);
#endif #endif