Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (3)
......@@ -1541,8 +1541,15 @@ TESTS = base_model_test
if HAVE_QT_QTEST
LIBVLC = -L../../../lib -lvlc
QT_QTEST_COMMON_cppflags = $(libqt_plugin_la_CPPFLAGS) -I$(builddir)/tests -DTOP_BUILDDIR=\"$(abs_top_builddir)\"
QT_QTEST_COMMON_cxxflags = $(AM_CXXFLAGS) $(QT_CFLAGS) $(QT_QTEST_CFLAGS) -fPIC $(CXXFLAGS_qt)
QT_QTEST_COMMON_ldadd = $(QT_LIBS) $(LIBS_qt) $(QT_QTEST_LIBS) $(LIBVLCCORE) $(LIBVLC)
QT_QTEST_COMMON_ldflags = $(AM_LDFLAGS) $(QT_LDFLAGS) $(QT_QTEST_LDFLAGS)
# test_renderer_manager_model
test_renderer_manager_model_SOURCES = \
tests/vlc_stub_modules.cpp \
tests/test_renderer_manager_model.cpp \
util/renderer_manager.hpp util/renderer_manager.cpp
......@@ -1552,13 +1559,33 @@ nodist_test_renderer_manager_model_SOURCES = \
BUILT_SOURCES += tests/test_renderer_manager_model.moc
CLEANFILES += tests/test_renderer_manager_model.moc
test_renderer_manager_model_CPPFLAGS = $(libqt_plugin_la_CPPFLAGS) -I$(builddir)/tests -DTOP_BUILDDIR=\"$(abs_top_builddir)\"
test_renderer_manager_model_CXXFLAGS = $(AM_CXXFLAGS) $(QT_CFLAGS) $(QT_QTEST_CFLAGS) -fPIC $(CXXFLAGS_qt)
test_renderer_manager_model_LDADD = $(QT_LIBS) $(LIBS_qt) $(QT_QTEST_LIBS) $(LIBVLCCORE) $(LIBVLC)
test_renderer_manager_model_LDFLAGS = $(AM_LDFLAGS) $(QT_LDFLAGS) $(QT_QTEST_LDFLAGS)
test_renderer_manager_model_CPPFLAGS = $(QT_QTEST_COMMON_cppflags)
test_renderer_manager_model_CXXFLAGS = $(QT_QTEST_COMMON_cxxflags)
test_renderer_manager_model_LDADD = $(QT_QTEST_COMMON_ldadd)
test_renderer_manager_model_LDFLAGS = $(QT_QTEST_COMMON_ldflags)
check_PROGRAMS += test_renderer_manager_model
TESTS += test_renderer_manager_model
# test_vlc_dialog_model
test_vlc_dialog_model_SOURCES = \
tests/vlc_stub_modules.cpp \
tests/test_vlc_dialog_model.cpp \
dialogs/dialogs/dialogmodel.cpp
nodist_test_vlc_dialog_model_SOURCES = \
tests/test_vlc_dialog_model.moc \
dialogs/dialogs/dialogmodel.moc.cpp
BUILT_SOURCES += tests/test_vlc_dialog_model.moc
CLEANFILES += tests/test_vlc_dialog_model.moc
test_vlc_dialog_model_CPPFLAGS = $(QT_QTEST_COMMON_cppflags)
test_vlc_dialog_model_CXXFLAGS = $(QT_QTEST_COMMON_cxxflags)
test_vlc_dialog_model_LDADD = $(QT_QTEST_COMMON_ldadd)
test_vlc_dialog_model_LDFLAGS = $(QT_QTEST_COMMON_ldflags)
check_PROGRAMS += test_vlc_dialog_model
TESTS += test_vlc_dialog_model
endif
QML_LOG_COMPILER = $(builddir)/qml_test -input
......
......@@ -23,6 +23,7 @@
// VLC includes
#include <vlc_dialog.h>
#include "qt.hpp"
#include <QThread>
#include "maininterface/mainctx.hpp"
......@@ -155,115 +156,158 @@ void DialogErrorModel::resetRepeatedMessageCount()
// DialogModel
//=================================================================================================
DialogModel::DialogModel(QObject* parent)
: QObject(parent)
{
}
//static functions
namespace {
DialogModel::~DialogModel()
void onDialogLogin(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
const char * psz_default_username, bool b_ask_store)
{
if (m_ctx)
vlc_dialog_provider_set_callbacks(m_ctx->getIntf(), nullptr, nullptr);
VLCDialogModel * model = static_cast<VLCDialogModel *>(p_data);
model->dialogCallback(dialogId, [=](VLCDialog* provider){
emit provider->login(dialogId, psz_title, psz_text, psz_default_username, b_ask_store);
});
}
MainCtx* DialogModel::getCtx() const
void onDialogQuestion(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
vlc_dialog_question_type i_type,
const char * psz_cancel, const char * psz_action1,
const char * psz_action2)
{
return m_ctx;
auto model = static_cast<VLCDialogModel *>(p_data);
model->dialogCallback(dialogId, [=](VLCDialog* provider){
emit provider->question(
dialogId, psz_title, psz_text,
static_cast<VLCDialog::QuestionType>(i_type), psz_cancel,
psz_action1, psz_action2);
});
}
void DialogModel::setCtx(MainCtx* ctx)
void onDialogProgress(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
bool b_indeterminate, float f_position,
const char * psz_cancel)
{
if (ctx == m_ctx)
return;
if (ctx) {
m_ctx = ctx;
const vlc_dialog_cbs cbs =
{
onLogin, onQuestion, onProgress, onCancelled, onProgressUpdated
};
vlc_dialog_provider_set_callbacks(ctx->getIntf(), &cbs, this);
} else {
if (m_ctx)
vlc_dialog_provider_set_callbacks(m_ctx->getIntf(), nullptr, nullptr);
m_ctx = nullptr;
}
emit ctxChanged();
auto model = static_cast<VLCDialogModel*>(p_data);
model->dialogCallback(dialogId, [=](VLCDialog* provider){
emit provider->progress(dialogId, psz_title, psz_text, b_indeterminate, f_position, psz_cancel);
});
}
//-------------------------------------------------------------------------------------------------
// Interface
//-------------------------------------------------------------------------------------------------
/* Q_INVOKABLE */ void DialogModel::post_login(DialogId dialogId, const QString & username,
const QString & password, bool store)
void onDialogProgressUpdated(void * p_data, vlc_dialog_id * dialogId,
float f_value, const char * psz_text)
{
vlc_dialog_id_post_login(dialogId.m_id, qtu(username), qtu(password), store);
auto model = static_cast<VLCDialogModel*>(p_data);
model->dialogCallback(dialogId, [=](VLCDialog* provider){
emit provider->progressUpdated(dialogId, f_value, psz_text);
});
}
/* Q_INVOKABLE */ void DialogModel::post_action1(DialogId dialogId)
void onDialogCancelled(void * p_data, vlc_dialog_id * dialogId)
{
vlc_dialog_id_post_action(dialogId.m_id, 1);
auto model = static_cast<VLCDialogModel*>(p_data);
model->dialogCallback(dialogId, [=](VLCDialog* provider){
emit provider->cancelled(dialogId);
});
}
/* Q_INVOKABLE */ void DialogModel::post_action2(DialogId dialogId)
{
vlc_dialog_id_post_action(dialogId.m_id, 2);
}
/* Q_INVOKABLE */ void DialogModel::dismiss(DialogId dialogId)
VLCDialogModel::VLCDialogModel(qt_intf_t* intf, QObject* parent)
: QObject(parent)
, m_intf(intf)
{
vlc_dialog_id_dismiss(dialogId.m_id);
const vlc_dialog_cbs cbs =
{
onDialogLogin, onDialogQuestion, onDialogProgress,
onDialogCancelled, onDialogProgressUpdated
};
vlc_dialog_provider_set_callbacks(intf, &cbs, this);
}
//-------------------------------------------------------------------------------------------------
// Private static functions
//-------------------------------------------------------------------------------------------------
/* static */ void DialogModel::onLogin(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
const char * psz_default_username, bool b_ask_store)
VLCDialogModel::~VLCDialogModel()
{
DialogModel * model = static_cast<DialogModel *>(p_data);
m_shuttingDown = true;
m_providerWait.wakeAll();
vlc_dialog_provider_set_callbacks(m_intf, nullptr, nullptr);
emit model->login(dialogId, psz_title, psz_text, psz_default_username, b_ask_store);
//ensure that we are not destroying ourselve before
{
QMutexLocker lock(&m_lock);
while (m_pendingDialog > 0)
m_pendingDialogCond.wait(&m_lock);
}
}
/* static */ void DialogModel::onQuestion(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
vlc_dialog_question_type i_type,
const char * psz_cancel, const char * psz_action1,
const char * psz_action2)
VLCDialog* VLCDialogModel::getProvider() const
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->question(dialogId, psz_title, psz_text, static_cast<int>(i_type), psz_cancel,
psz_action1, psz_action2);
return m_provider;
}
/* static */ void DialogModel::onProgress(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
bool b_indeterminate, float f_position,
const char * psz_cancel)
void VLCDialogModel::setProvider(VLCDialog* provider)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
if (m_provider == provider)
return;
if (m_provider)
{
disconnect(m_provider, nullptr, this, nullptr);
}
m_provider = provider;
if (m_provider)
{
connect(m_provider, &VLCDialog::post_login,
this, [](DialogId dialogId, const QString & username,
const QString & password, bool store){
vlc_dialog_id_post_login(dialogId.m_id, qtu(username), qtu(password), store);
});
connect(m_provider, &VLCDialog::post_action1,
this, [](DialogId dialogId){
vlc_dialog_id_post_action(dialogId.m_id, 1);
});
connect(m_provider, &VLCDialog::post_action2,
this, [](DialogId dialogId){
vlc_dialog_id_post_action(dialogId.m_id, 2);
});
connect(m_provider, &VLCDialog::dismiss,
this, [](DialogId dialogId){
vlc_dialog_id_dismiss(dialogId.m_id);
});
emit model->progress(dialogId, psz_title, psz_text, b_indeterminate, f_position, psz_cancel);
}
m_providerWait.wakeAll();
emit providerChanged();
}
/* static */ void DialogModel::onProgressUpdated(void * p_data, vlc_dialog_id * dialogId,
float f_value, const char * psz_text)
void VLCDialogModel::dialogCallback(vlc_dialog_id * dialogId, std::function<void(VLCDialog* provider)> callback)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
QMutexLocker lock(&m_lock);
m_pendingDialog++;
//dialogs are synchronous calls, if they are spawned from qt thread
//(which shouldn't happen), we can't wait for m_provider
if (QThread::currentThread() == this->thread() && m_provider == nullptr)
{
vlc_dialog_id_dismiss(dialogId);
m_pendingDialog--;
m_pendingDialogCond.wakeOne();
return;
}
emit model->progressUpdated(dialogId, f_value, psz_text);
}
while (m_provider == nullptr && !m_shuttingDown)
m_providerWait.wait(&m_lock);
/* static */ void DialogModel::onCancelled(void * p_data, vlc_dialog_id * dialogId)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
if (m_shuttingDown)
{
vlc_dialog_id_dismiss(dialogId);
m_pendingDialog--;
m_pendingDialogCond.wakeOne();
return;
}
callback(m_provider);
emit model->cancelled(dialogId);
m_pendingDialog--;
m_pendingDialogCond.wakeOne();
}
......@@ -31,6 +31,9 @@
// Qt includes
#include <QAbstractListModel>
#include <QQmlEngine>
#include <QMutex>
#include <QWaitCondition>
#include "qt.hpp"
#include "util/singleton.hpp"
......@@ -119,59 +122,40 @@ private: // Variables
friend class Singleton<DialogErrorModel>;
};
class DialogModel : public QObject
/**
* this class expose vlc_dialog events and allow to reply
* to use it, instantiate the object, connect the signals then
* register it in VLCDialogModel
*/
class VLCDialog: public QObject
{
Q_OBJECT
Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
public: // Enums
// NOTE: Is it really useful to have this declared here ?
enum QuestionType { QUESTION_NORMAL, QUESTION_WARNING, QUESTION_CRITICAL };
Q_ENUM(QuestionType)
public:
explicit DialogModel(QObject *parent = nullptr);
~DialogModel();
enum QuestionType {
QUESTION_NORMAL = VLC_DIALOG_QUESTION_NORMAL,
QUESTION_WARNING = VLC_DIALOG_QUESTION_WARNING,
QUESTION_CRITICAL = VLC_DIALOG_QUESTION_CRITICAL
};
Q_ENUM(QuestionType)
public: // Interface
signals:
//dialog user actions
Q_INVOKABLE void post_login(DialogId dialogId, const QString & username,
const QString & password, bool store = false);
const QString & password, bool store = false);
Q_INVOKABLE void post_action1(DialogId dialogId);
Q_INVOKABLE void post_action2(DialogId dialogId);
Q_INVOKABLE void dismiss(DialogId dialogId);
private: // Static functions
static void onLogin(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, const char * psz_default_username,
bool b_ask_store);
static void onQuestion(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, vlc_dialog_question_type i_type,
const char * psz_cancel, const char * psz_action1,
const char * psz_action2);
//dialog request
static void onProgress(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, bool b_indeterminate, float f_position,
const char *psz_cancel);
static void onProgressUpdated(void * p_data, vlc_dialog_id * dialogId, float f_value,
const char * psz_text);
static void onCancelled(void * p_data, vlc_dialog_id * dialogId);
public:
MainCtx* getCtx() const;
void setCtx(MainCtx*);
signals:
void login(DialogId dialogId, const QString & title,
const QString & text, const QString & defaultUsername,
bool b_ask_store);
void question(DialogId dialogId, const QString & title, const QString & text, int type,
void question(DialogId dialogId, const QString & title, const QString & text, QuestionType type,
const QString & cancel, const QString & action1, const QString & action2);
void progress(DialogId dialogId, const QString & title, const QString & text,
......@@ -180,11 +164,46 @@ signals:
void progressUpdated(DialogId dialogId, float f_value, const QString & text);
void cancelled(DialogId dialogId);
};
void ctxChanged();
/**
* This class listen to vlc_dialog_t events and forward them to VLCDialog
*/
class VLCDialogModel : public QObject, public Singleton<VLCDialogModel>
{
Q_OBJECT
Q_PROPERTY(VLCDialog* provider READ getProvider WRITE setProvider NOTIFY providerChanged FINAL)
public:
explicit VLCDialogModel(qt_intf_t* intf, QObject *parent = nullptr);
~VLCDialogModel();
public:
VLCDialog* getProvider() const;
void setProvider(VLCDialog*);
public:
//block dialog until m_provider is available the call the callback on it
void dialogCallback(vlc_dialog_id*, std::function<void(VLCDialog* provider)>);
signals:
void providerChanged();
private:
MainCtx* m_ctx = nullptr;
qt_intf_t* m_intf = nullptr;
QMutex m_lock;
//waiting for the provider to be set
QWaitCondition m_providerWait;
//during destruction, waiting for dialogCallback to finish
QWaitCondition m_pendingDialogCond;
unsigned m_pendingDialog = 0;
VLCDialog* m_provider = nullptr;
bool m_shuttingDown = false;
friend class Singleton<VLCDialogModel>;
};
#endif // DIALOGMODEL_HPP
......@@ -53,10 +53,10 @@ Item {
Component.onDestruction: {
if (questionDialog.dialogId !== null) {
dialogModel.dismiss(questionDialog.dialogId)
vlcDialog.dismiss(questionDialog.dialogId)
questionDialog.dialogId = null
} if (loginDialog.dialogId !== null) {
dialogModel.dismiss(loginDialog.dialogId)
vlcDialog.dismiss(loginDialog.dialogId)
loginDialog.dialogId = null
}
}
......@@ -73,18 +73,26 @@ Item {
// Connections
//---------------------------------------------------------------------------------------------
Connections
VLCDialog
{
target: dialogModel
id: vlcDialog
Component.onCompleted: {
VLCDialogModel.provider = vlcDialog
}
Component.onDestruction: {
VLCDialogModel.provider = null
}
function onLogin(dialogId, title, text, defaultUsername, askStore) {
onLogin: (dialogId, title, text, defaultUsername, askStore) => {
loginDialog.dialogId = dialogId
loginDialog.title = title
loginDialog.defaultUsername = defaultUsername
loginDialog.open()
}
function onQuestion(dialogId, title, text, type, cancel, action1, action2) {
onQuestion: (dialogId, title, text, type, cancel, action1, action2) => {
questionDialog.dialogId = dialogId
questionDialog.title = title
questionDialog.text = text
......@@ -94,7 +102,7 @@ Item {
questionDialog.open()
}
function onProgress(dialogId, title, text, indeterminate, position, cancel) {
onProgress: (dialogId, title, text, indeterminate, position, cancel) => {
progressDialog.dialogId = dialogId
progressDialog.title = title
progressDialog.text = text
......@@ -104,7 +112,7 @@ Item {
progressDialog.open()
}
function onProgressUpdated(dialogId, position, text) {
onProgressUpdated: (dialogId, position, text) => {
if (progressDialog.dialogId !== dialogId) {
console.warn("progress event on an inexisting dialog")
return
......@@ -113,21 +121,21 @@ Item {
progressDialog.position = position
}
function onCancelled(dialogId) {
onCancelled: (dialogId) => {
if (questionDialog.dialogId === dialogId) {
questionDialog.close()
questionDialog.dialogId = null
dialogModel.dismiss(dialogId)
dismiss(dialogId)
} else if (loginDialog.dialogId === dialogId) {
loginDialog.close()
loginDialog.dialogId = null
dialogModel.dismiss(dialogId)
dismiss(dialogId)
} else if (progressDialog.dialogId === dialogId) {
progressDialog.close()
progressDialog.dialogId = null
dialogModel.dismiss(dialogId)
dismiss(dialogId)
} else {
dialogModel.dismiss(dialogId)
dismiss(dialogId)
}
}
}
......@@ -146,12 +154,6 @@ Item {
// Childs
//---------------------------------------------------------------------------------------------
DialogModel {
id: dialogModel
ctx: MainCtx
}
Widgets.DrawerExt {
id: errorPopup
......@@ -391,13 +393,13 @@ Item {
onAccepted: {
if (loginDialog.dialogId !== null) {
dialogModel.post_login(loginDialog.dialogId, username.text, password.text, savePassword.checked)
vlcDialog.post_login(loginDialog.dialogId, username.text, password.text, savePassword.checked)
loginDialog.dialogId = null
}
}
onRejected: {
if (loginDialog.dialogId !== null) {
dialogModel.dismiss(loginDialog.dialogId)
vlcDialog.dismiss(loginDialog.dialogId)
loginDialog.dialogId = null
}
}
......@@ -466,7 +468,7 @@ Item {
text: progressDialog.cancelTxt
onClicked: {
dialogModel.dismiss(progressDialog.dialogId)
vlcDialog.dismiss(progressDialog.dialogId)
progressDialog.dialogId = null
progressDialog.close()
}
......@@ -529,7 +531,7 @@ Item {
Keys.onPressed: (event) => Navigation.defaultKeyAction(event)
onClicked: {
dialogModel.dismiss(questionDialog.dialogId)
vlcDialog.dismiss(questionDialog.dialogId)
questionDialog.dialogId = null
questionDialog.close()
}
......@@ -548,7 +550,7 @@ Item {
Keys.onPressed: (event) => Navigation.defaultKeyAction(event)
onClicked: {
dialogModel.post_action1(questionDialog.dialogId)
vlcDialog.post_action1(questionDialog.dialogId)
questionDialog.dialogId = null
questionDialog.close()
}
......@@ -565,7 +567,7 @@ Item {
Keys.onPressed: (event) => Navigation.defaultKeyAction(event)
onClicked: {
dialogModel.post_action2(questionDialog.dialogId)
vlcDialog.post_action2(questionDialog.dialogId)
questionDialog.dialogId = null
questionDialog.close()
}
......
......@@ -128,6 +128,8 @@ MainUI::MainUI(qt_intf_t *p_intf, MainCtx *mainCtx, QWindow* interfaceWindow, Q
assert(m_intf->p_mainPlaylistController);
SingletonRegisterHelper<PlaylistController>::setInstance(m_intf->p_mainPlaylistController);
assert(VLCDialogModel::getInstance<false>());
SingletonRegisterHelper<VLCDialogModel>::setInstance(VLCDialogModel::getInstance<false>());
assert(DialogsProvider::getInstance());
SingletonRegisterHelper<DialogsProvider>::setInstance(DialogsProvider::getInstance());
......@@ -252,7 +254,8 @@ void MainUI::registerQMLTypes()
// @uri VLC.Dialogs
qmlRegisterType<AboutModel>( uri, versionMajor, versionMinor, "AboutModel" );
qmlRegisterType<DialogModel>(uri, versionMajor, versionMinor, "DialogModel");
qmlRegisterType<VLCDialog>( uri, versionMajor, versionMinor, "VLCDialog" );
qmlRegisterSingletonType<VLCDialogModel>(uri, versionMajor, versionMinor, "VLCDialogModel", SingletonRegisterHelper<VLCDialogModel>::callback);
qmlRegisterUncreatableType<DialogId>( uri, versionMajor, versionMinor, "dialogId", "");
qmlRegisterSingletonType<DialogsProvider>(uri, versionMajor, versionMinor, "DialogsProvider", SingletonRegisterHelper<DialogsProvider>::callback);
qmlRegisterSingletonType<DialogErrorModel>(uri, versionMajor, versionMinor, "DialogErrorModel", SingletonRegisterHelper<DialogErrorModel>::callback);
......
......@@ -1107,6 +1107,7 @@ if qt6_dep.found()
vlc_tests += {
'name': 'test_qt_renderer_manager',
'sources': files(
'tests/vlc_stub_modules.cpp',
'tests/test_renderer_manager_model.cpp',
'util/renderer_manager.hpp',
'util/renderer_manager.cpp'
......@@ -1120,7 +1121,28 @@ if qt6_dep.found()
'suite': ['qt'],
'include_directories' : qt_include_dir,
'link_with': [libvlccore, libvlc],
'dependencies': [qt6_dep, qt_extra_deps, qtest_qt6_dep]
}
vlc_tests += {
'name': 'test_qt_dialog_model',
'sources': files(
'tests/vlc_stub_modules.cpp',
'tests/test_vlc_dialog_model.cpp',
'dialogs/dialogs/dialogmodel.hpp',
'dialogs/dialogs/dialogmodel.cpp'
),
'moc_sources': files(
'tests/test_vlc_dialog_model.cpp'
),
'moc_headers': files(
'dialogs/dialogs/dialogmodel.hpp'
),
'suite': ['qt'],
'include_directories' : qt_include_dir,
'link_with': [libvlccore, libvlc],
'dependencies': [qt6_dep, qt_extra_deps, qtest_qt6_dep],
}
endif
endif
......@@ -1010,6 +1010,7 @@ static void *Thread( void *obj )
app.setDesktopFileName( PACKAGE );
DialogErrorModel::getInstance( p_intf );
VLCDialogModel::getInstance( p_intf );
/* Initialize the Dialog Provider and the Main Input Manager */
DialogsProvider::getInstance( p_intf );
......@@ -1143,6 +1144,7 @@ static void *ThreadCleanup( qt_intf_t *p_intf, CleanupReason cleanupReason )
*/
DialogsProvider::killInstance();
VLCDialogModel::killInstance();
DialogErrorModel::killInstance();
/* Destroy the main playlist controller */
......
......@@ -15,123 +15,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Define a builtin module for mocked parts */
#define MODULE_NAME renderer_manager_test
#undef VLC_DYNAMIC_PLUGIN
#include "../../../../test/libvlc/test.h"
#include <vlc/vlc.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_playlist.h>
#include <vlc_services_discovery.h>
#include <vlc_renderer_discovery.h>
#include <vlc_probe.h>
#include <vlc_interface.h>
#include <vlc_player.h>
#include "../../../../lib/libvlc_internal.h"
#include "qt.hpp"
namespace vlc {
class Compositor {};
}
static vlc_renderer_discovery_t* g_rd = nullptr;
static bool g_rd_probe_enabled = false;
static int OpenRD( vlc_object_t* p_this )
{
g_rd = (vlc_renderer_discovery_t *)p_this;
return VLC_SUCCESS;
}
static void CloseRD( vlc_object_t* )
{
g_rd = nullptr;
}
static int vlc_rd_probe_open(vlc_object_t *obj) {
auto probe = (struct vlc_probe_t *)obj;
if (g_rd_probe_enabled)
vlc_rd_probe_add(probe, "rd", "a fake renderer for testing purpose");
//only probe ourself
return VLC_PROBE_STOP;
}
static qt_intf_t* g_intf = nullptr;
static int OpenIntf(vlc_object_t* p_this)
{
auto intfThread = reinterpret_cast<intf_thread_t*>(p_this);
libvlc_int_t* libvlc = vlc_object_instance( p_this );
/* Ensure initialization of objects in qt_intf_t. */
g_intf = vlc_object_create<qt_intf_t>( libvlc );
if (!g_intf)
return VLC_ENOMEM;
g_intf->obj.logger = vlc_LogHeaderCreate(libvlc->obj.logger, "qt");
if (!g_intf->obj.logger)
{
vlc_object_delete(g_intf);
return VLC_EGENERIC;
}
g_intf->intf = intfThread;
intfThread->p_sys = reinterpret_cast<intf_sys_t*>(g_intf);
return VLC_SUCCESS;
}
static void CloseIntf( vlc_object_t *p_this )
{
intf_thread_t* intfThread = (intf_thread_t*)(p_this);
auto p_intf = reinterpret_cast<qt_intf_t*>(intfThread->p_sys);
if (!p_intf)
return;
vlc_LogDestroy(p_intf->obj.logger);
vlc_object_delete(p_intf);
}
vlc_module_begin()
set_callbacks(OpenIntf, CloseIntf)
set_capability("interface", 0)
add_submodule()
set_capability("renderer_discovery", 0)
add_shortcut("rd")
set_callbacks(OpenRD, CloseRD)
add_submodule()
set_capability("renderer probe", 10000)
set_callback(vlc_rd_probe_open)
vlc_module_end()
extern "C" {
const char vlc_module_name[] = MODULE_STRING;
VLC_EXPORT vlc_plugin_cb vlc_static_modules[] = {
VLC_SYMBOL(vlc_entry),
NULL
};
}
#include <QTest>
#include <QAbstractItemModelTester>
#include "vlc_stub_modules.hpp"
#include "../util/renderer_manager.hpp"
#include <vlc_cxx_helpers.hpp>
using RendererItemPtr = vlc_shared_data_ptr_type(vlc_renderer_item_t,
vlc_renderer_item_hold,
vlc_renderer_item_release);
class TestClass : public QObject
{
Q_OBJECT
......@@ -143,7 +37,7 @@ private:
RendererItemPtr item(vlc_renderer_item_new(
"type", qtu(name), qtu(sout), "extra sout",
nullptr, "icon://", i ));
vlc_rd_add_item( g_rd, item.get() );
vlc_rd_add_item( rd(), item.get() );
return item;
}
......@@ -158,47 +52,49 @@ private:
QCOMPARE(m_model->data(idx, RendererManager::FLAGS), id);
}
vlc_renderer_discovery_t* rd() const
{
return m_env->renderDiscovery;
}
private slots:
void initTestCase() {
test_init();
m_vlc = libvlc_new(test_defaults_nargs, test_defaults_args);
libvlc_InternalAddIntf(m_vlc->p_libvlc_int, MODULE_STRING);
libvlc_InternalPlay(m_vlc->p_libvlc_int);
m_playlist = vlc_intf_GetMainPlaylist(g_intf->intf);
m_player = vlc_playlist_GetPlayer( m_playlist );
m_env = std::make_unique<VLCTestingEnv>();
QVERIFY(m_env->init());
m_player = m_env->intf->p_player;
}
void cleanupTestCase() {
libvlc_release(m_vlc);
m_player = nullptr;
m_env.reset();
}
void init() {
g_rd_probe_enabled = true;
m_model = new RendererManager(g_intf, m_player);
m_env->renderDiscoveryProbeEnabled = true;
m_model = new RendererManager(m_env->intf, m_player);
//QAbstractItemModelTester checks that QAbstractItemModel events are coherents
m_modelTester = new QAbstractItemModelTester(m_model);
QVERIFY(g_rd == nullptr);
m_modelTester = std::make_unique<QAbstractItemModelTester>(m_model);
QVERIFY(rd() == nullptr);
}
void cleanup() {
delete m_modelTester;
m_modelTester.reset();
delete m_model;
QVERIFY(g_rd == nullptr);
QVERIFY(rd() == nullptr);
}
void testEmpty() {
QVERIFY(g_rd == nullptr);
QVERIFY(rd() == nullptr);
//model is empty before scan
QCOMPARE(m_model->rowCount(), 0);
m_model->StartScan();
QVERIFY(g_rd != nullptr);
QVERIFY(rd() != nullptr);
QCOMPARE(m_model->rowCount(), 0);
QCOMPARE(m_model->getStatus(), RendererManager::RUNNING);
//scan didn't find anything
m_model->StopScan();
QVERIFY(g_rd == nullptr);
QVERIFY(rd() == nullptr);
QCOMPARE(m_model->rowCount(), 0);
QCOMPARE(m_model->getStatus(), RendererManager::IDLE);
}
......@@ -209,7 +105,7 @@ private slots:
QCOMPARE(m_model->rowCount(), 0);
QCOMPARE(m_model->getStatus(), RendererManager::RUNNING);
QVERIFY(g_rd != nullptr);
QVERIFY(rd() != nullptr);
for (int i = 0; i < 5; ++i) {
pushDummyRDItem(i);
......@@ -227,12 +123,12 @@ private slots:
}
//module is closed
QVERIFY(g_rd == nullptr);
QVERIFY(rd() == nullptr);
}
void testTwoPassesIdentical() {
m_model->StartScan();
QVERIFY(g_rd != nullptr);
QVERIFY(rd() != nullptr);
QCOMPARE(m_model->rowCount(), 0);
for (int i = 0; i < 5; ++i) {
pushDummyRDItem(i);
......@@ -290,7 +186,7 @@ private slots:
pushDummyRDItem(i);
}
QCOMPARE(m_model->rowCount(), 7);
vlc_rd_remove_item(g_rd, item.get());
vlc_rd_remove_item(rd(), item.get());
QCOMPARE(m_model->rowCount(), 6);
m_model->StopScan();
QCOMPARE(m_model->rowCount(), 6);
......@@ -423,7 +319,7 @@ private slots:
//selected item is removed
QCOMPARE(m_model->rowCount(), 5);
vlc_rd_remove_item( g_rd, r3.get() );
vlc_rd_remove_item( rd(), r3.get() );
//item is held by model
QCOMPARE(m_model->useRenderer(), true);
......@@ -439,11 +335,11 @@ private slots:
//item should be gone after next scan
m_model->StartScan();
vlc_rd_add_item( g_rd, r0.get() );
vlc_rd_add_item( g_rd, r1.get() );
vlc_rd_add_item( g_rd, r2.get() );
vlc_rd_add_item( rd(), r0.get() );
vlc_rd_add_item( rd(), r1.get() );
vlc_rd_add_item( rd(), r2.get() );
//no r3
vlc_rd_add_item( g_rd, r4.get() );
vlc_rd_add_item( rd(), r4.get() );
m_model->StopScan();
QCOMPARE(m_model->rowCount(), 4);
......@@ -451,8 +347,8 @@ private slots:
selidx = m_model->index(2);
m_model->setData(selidx, true, RendererManager::SELECTED);
m_model->StartScan();
vlc_rd_add_item( g_rd, r0.get() );
vlc_rd_add_item( g_rd, r1.get() );
vlc_rd_add_item( rd(), r0.get() );
vlc_rd_add_item( rd(), r1.get() );
m_model->StopScan();
QCOMPARE(m_model->rowCount(), 3);
QCOMPARE(m_model->data(selidx, RendererManager::SELECTED), true);
......@@ -472,20 +368,20 @@ private slots:
//failed state when no renderer manager is found
void testNoProbes() {
g_rd_probe_enabled = false;
m_env->renderDiscoveryProbeEnabled = false;
QCOMPARE(m_model->getStatus(), RendererManager::IDLE);
m_model->StartScan();
QCOMPARE(m_model->getStatus(), RendererManager::FAILED);
QCOMPARE(m_model->rowCount(), 0);
QVERIFY(g_rd == nullptr);
g_rd_probe_enabled = true;
QVERIFY(rd() == nullptr);
m_env->renderDiscoveryProbeEnabled = true;
}
private:
libvlc_instance_t* m_vlc = nullptr;
vlc_playlist_t* m_playlist = nullptr;
std::unique_ptr<VLCTestingEnv> m_env;
vlc_player_t* m_player = nullptr;
QAbstractItemModelTester* m_modelTester = nullptr;
RendererManager* m_model;
std::unique_ptr<QAbstractItemModelTester> m_modelTester;
RendererManager* m_model = nullptr;
};
QTEST_GUILESS_MAIN(TestClass)
......
/*****************************************************************************
* Copyright (C) 2024 VLC authors and VideoLAN
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "vlc_stub_modules.hpp"
#include <QTest>
#include <QSignalSpy>
#include <QThreadPool>
#include "dialogs/dialogs/dialogmodel.hpp"
#include <vlc_cxx_helpers.hpp>
#include "../util/renderer_manager.hpp"
class TestVLCDialogModel : public QObject
{
Q_OBJECT
enum UserAnswer {
Dismiss,
PostLogin,
PostAction1,
PostAction2
};
private slots:
void initTestCase() {
m_env = std::make_unique<VLCTestingEnv>();
QVERIFY(m_env->init());
m_intf = m_env->intf;
}
void cleanupTestCase() {
m_intf = nullptr;
m_env.reset();
}
void init() {
VLCDialogModel::getInstance(m_intf);
m_dialog = new VLCDialog();
m_loginSpy = std::make_unique<QSignalSpy>(m_dialog, &VLCDialog::login);
m_questionSpy = std::make_unique<QSignalSpy>(m_dialog, &VLCDialog::question);
m_progressSpy = std::make_unique<QSignalSpy>(m_dialog, &VLCDialog::progress);
m_progressUpdatedSpy = std::make_unique<QSignalSpy>(m_dialog, &VLCDialog::progressUpdated);
m_canceledSpy = std::make_unique<QSignalSpy>(m_dialog, &VLCDialog::cancelled);
}
void cleanup() {
m_loginSpy.reset();
m_questionSpy.reset();
m_progressSpy.reset();
m_progressUpdatedSpy.reset();
m_canceledSpy.reset();
VLCDialogModel* model = VLCDialogModel::getInstance<false>();
if (model) {
model->setProvider(nullptr);
VLCDialogModel::killInstance();
}
delete m_dialog;
}
void testLogin_data() {
QTest::addColumn<UserAnswer>("userReply");
QTest::addColumn<int>("expectedReply");
QTest::newRow("login") << PostLogin << 1;
QTest::newRow("dismiss") << Dismiss << 0;
QTest::newRow("wrongAnswer") << PostAction1 << VLC_EGENERIC;
}
//failed state when no renderer manager is found
void testLogin() {
QFETCH(UserAnswer, userReply);
QFETCH(int, expectedReply);
QObject::connect(m_dialog, &VLCDialog::login, this, [&](
DialogId dialogId, const QString & title,
const QString & text, const QString & defaultUsername,
bool){
QCOMPARE(defaultUsername, "default username");
QCOMPARE(title, "login title");
QCOMPARE(text, "login message");
switch(userReply)
{
case Dismiss:
m_dialog->dismiss(dialogId);
break;
case PostLogin:
m_dialog->post_login(dialogId, "username", "hunter2", false);
break;
case PostAction1:
default:
//bad behavior
m_dialog->post_action1(dialogId);
break;
}
});
VLCDialogModel::getInstance<false>()->setProvider(m_dialog);
std::atomic<bool> replied = false;
int reply = -1;
QString repliedUsername;
QString repliedPassword;
bool repliedStore = true;
QThreadPool::globalInstance()->start([&](){
char* username = nullptr;
char* password = nullptr;
reply = vlc_dialog_wait_login(m_intf, &username, &password, &repliedStore,
"default username", "login title",
"login message");
if (reply == 1) {
repliedUsername = username;
repliedPassword = password;
free(username);
free(password);
}
replied = true;
});
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
if (expectedReply == VLC_EGENERIC)
QCOMPARE_LT(reply, 0);
else
QCOMPARE(reply, expectedReply);
if (reply == 1) {
QCOMPARE(repliedUsername, "username");
QCOMPARE(repliedPassword, "hunter2");
QCOMPARE(repliedStore, false);
}
QCOMPARE(m_questionSpy->count(), 0);
QCOMPARE(m_progressSpy->count(), 0);
QCOMPARE(m_progressUpdatedSpy->count(), 0);
QCOMPARE(m_canceledSpy->count(), 0);
}
void testQuestion_data() {
QTest::addColumn<UserAnswer>("userReply");
QTest::addColumn<int>("expectedReply");
QTest::newRow("action1") << PostAction1 << 1;
QTest::newRow("action2") << PostAction2 << 2;
QTest::newRow("dismiss") << Dismiss << 0;
QTest::newRow("wrongAnswer") << PostLogin << VLC_EGENERIC;
}
//failed state when no renderer manager is found
void testQuestion() {
QFETCH(UserAnswer, userReply);
QFETCH(int, expectedReply);
QObject::connect(m_dialog, &VLCDialog::question, this,
[&](DialogId dialogId, const QString& title,
const QString& text, VLCDialog::QuestionType type,
const QString& cancel, const QString& action1, const QString& action2){
QCOMPARE(action1, "action1 txt");
QCOMPARE(action2, "action2 txt");
QCOMPARE(cancel, "cancel txt");
QCOMPARE(title, "title");
QCOMPARE(text, "message");
QCOMPARE(type, VLCDialog::QuestionType::QUESTION_WARNING);
switch(userReply)
{
case PostAction1:
m_dialog->post_action1(dialogId);
break;
case PostAction2:
m_dialog->post_action2(dialogId);
break;
case Dismiss:
m_dialog->dismiss(dialogId);
break;
case PostLogin:
m_dialog->post_login(dialogId, "not", "expected"); //user answer the type
break;
}
});
VLCDialogModel::getInstance<false>()->setProvider(m_dialog);
std::atomic<bool> replied = false;
int reply = -1;
QThreadPool::globalInstance()->start([&](){
reply = vlc_dialog_wait_question(m_intf, VLC_DIALOG_QUESTION_WARNING,
"cancel txt", "action1 txt",
"action2 txt", "title", "message");
replied = true;
});
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
if (expectedReply == VLC_EGENERIC)
QCOMPARE_LT(reply, 0);
else
QCOMPARE(reply, expectedReply);
QCOMPARE(m_loginSpy->count(), 0);
QCOMPARE(m_progressSpy->count(), 0);
QCOMPARE(m_progressUpdatedSpy->count(), 0);
QCOMPARE(m_canceledSpy->count(), 0);
}
//failed state when no renderer manager is found
void testProgress() {
QObject::connect(m_dialog, &VLCDialog::progress, this,
[&](DialogId, const QString& title, const QString& text,
bool b_indeterminate, float f_position, const QString& cancel){
//QCOMPARE performs is fuzzy for floats
QCOMPARE(b_indeterminate, false);
QCOMPARE(f_position, 0.f);
QCOMPARE(cancel, "cancel txt");
QCOMPARE(title, "title");
QCOMPARE(text, "message");
});
QObject::connect(m_dialog, &VLCDialog::progressUpdated, this,
[&](DialogId, float f_position, const QString& text){
//QCOMPARE performs is fuzzy for floats
QCOMPARE(f_position, 0.3f);
QCOMPARE(text, "updated text");
});
VLCDialogModel::getInstance<false>()->setProvider(m_dialog);
std::atomic<bool> replied = false;
vlc_dialog_id* dialogId;
QThreadPool::globalInstance()->start([&](){
dialogId = vlc_dialog_display_progress(m_intf,
false, 0.f,
"cancel txt", "title", "message");
replied = true;
});
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
QVERIFY(dialogId != nullptr);
replied = false;
int reply;
QThreadPool::globalInstance()->start([&](){
reply = vlc_dialog_update_progress_text(m_intf, dialogId, 0.3f, "updated text");
replied = true;
});
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
QCOMPARE(reply, VLC_SUCCESS);
QCOMPARE(m_canceledSpy->count(), 0);
replied = false;
QThreadPool::globalInstance()->start([&](){
vlc_dialog_release(m_intf, dialogId);
replied = true;
});
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
QCOMPARE(m_canceledSpy->count(), 1);
QCOMPARE(m_loginSpy->count(), 0);
QCOMPARE(m_questionSpy->count(), 0);
}
void testLateBinding() {
QObject::connect(m_dialog, &VLCDialog::question, this,
[&](DialogId dialogId, const QString& ,
const QString& , VLCDialog::QuestionType ,
const QString& , const QString& , const QString& ){
m_dialog->post_action1(dialogId);
});
std::atomic<bool> replied = false;
int reply = -1;
QThreadPool::globalInstance()->start([&](){
reply = vlc_dialog_wait_question(m_intf, VLC_DIALOG_QUESTION_WARNING,
"cancel txt", "action1 txt",
"action2 txt", "title", "message");
replied = true;
});
//wait for the question to be asked
//the dialog should block until VLCDialog is provided
QTest::qWait(20);
//set the dialog afterwards
VLCDialogModel::getInstance<false>()->setProvider(m_dialog);
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
//user replied with Action1
QCOMPARE(reply, 1);
QCOMPARE(m_loginSpy->count(), 0);
QCOMPARE(m_progressSpy->count(), 0);
QCOMPARE(m_progressUpdatedSpy->count(), 0);
QCOMPARE(m_canceledSpy->count(), 0);
}
void testModelDestruction() {
std::atomic<bool> replied = false;
int reply = -1;
QThreadPool::globalInstance()->start([&](){
reply = vlc_dialog_wait_question(m_intf, VLC_DIALOG_QUESTION_WARNING,
"cancel txt", "action1 txt",
"action2 txt", "title", "message");
replied = true;
});
//wait for the question to be asked
//the dialog should block until VLCDialog is provided
QTest::qWait(20);
VLCDialogModel::killInstance();
QVERIFY(QTest::qWaitFor([&replied](){ return replied == true; }));
QCOMPARE(reply, 0);
}
void testSameThreadWithoutDialog()
{
int reply = vlc_dialog_wait_question(m_intf, VLC_DIALOG_QUESTION_WARNING,
"cancel txt", "action1 txt",
"action2 txt", "title", "message");
QCOMPARE(reply, 0);
}
void testSameThreadWithDialog()
{
QObject::connect(m_dialog, &VLCDialog::question, this,
[&](DialogId dialogId, const QString& ,
const QString& , VLCDialog::QuestionType ,
const QString& , const QString& , const QString& ){
m_dialog->post_action1(dialogId);
});
VLCDialogModel::getInstance<false>()->setProvider(m_dialog);
int reply = vlc_dialog_wait_question(m_intf, VLC_DIALOG_QUESTION_WARNING,
"cancel txt", "action1 txt",
"action2 txt", "title", "message");
QCOMPARE(reply, 1);
}
private:
std::unique_ptr<VLCTestingEnv> m_env;
qt_intf_t* m_intf = nullptr;
VLCDialog* m_dialog = nullptr;
std::unique_ptr<QSignalSpy> m_loginSpy;
std::unique_ptr<QSignalSpy> m_questionSpy;
std::unique_ptr<QSignalSpy> m_progressSpy;
std::unique_ptr<QSignalSpy> m_progressUpdatedSpy;
std::unique_ptr<QSignalSpy> m_canceledSpy;
};
QTEST_GUILESS_MAIN(TestVLCDialogModel)
#include "test_vlc_dialog_model.moc"
/*****************************************************************************
* Copyright (C) 2024 VLC authors and VideoLAN
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Define builtin modules for mocked parts */
#define MODULE_NAME module_faker
#undef VLC_DYNAMIC_PLUGIN
#include <vlc/vlc.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_playlist.h>
#include <vlc_services_discovery.h>
#include <vlc_renderer_discovery.h>
#include <vlc_probe.h>
#include <vlc_interface.h>
#include <vlc_player.h>
#include "../../../../lib/libvlc_internal.h"
#include "qt.hpp"
#include "vlc_stub_modules.hpp"
static VLCTestingEnv* testenv = nullptr;
///RenderDiscovery module
static int OpenRD( vlc_object_t* p_this )
{
testenv->renderDiscovery = (vlc_renderer_discovery_t *)p_this;
return VLC_SUCCESS;
}
static void CloseRD( vlc_object_t* )
{
testenv->renderDiscovery = nullptr;
}
static int vlc_rd_probe_open(vlc_object_t *obj) {
auto probe = (struct vlc_probe_t *)obj;
if (testenv->renderDiscoveryProbeEnabled)
vlc_rd_probe_add(probe, "rd", "a fake renderer for testing purpose");
//only probe ourself
return VLC_PROBE_STOP;
}
///Interface module
namespace vlc {
class Compositor {};
}
static int OpenIntf(vlc_object_t* p_this)
{
auto intfThread = reinterpret_cast<intf_thread_t*>(p_this);
libvlc_int_t* libvlc = vlc_object_instance( p_this );
/* Ensure initialization of objects in qt_intf_t. */
qt_intf_t* qt_intf = vlc_object_create<qt_intf_t>( libvlc );
if (!qt_intf)
return VLC_ENOMEM;
qt_intf->obj.logger = vlc_LogHeaderCreate(libvlc->obj.logger, "qt");
if (!qt_intf->obj.logger)
{
vlc_object_delete(qt_intf);
return VLC_EGENERIC;
}
qt_intf->p_playlist = vlc_intf_GetMainPlaylist(intfThread);
qt_intf->p_player = vlc_playlist_GetPlayer(qt_intf->p_playlist);
qt_intf->intf = intfThread;
intfThread->p_sys = reinterpret_cast<intf_sys_t*>(qt_intf);
testenv->intf = qt_intf;
return VLC_SUCCESS;
}
static void CloseIntf( vlc_object_t *p_this )
{
intf_thread_t* intfThread = (intf_thread_t*)(p_this);
auto qt_intf = reinterpret_cast<qt_intf_t*>(intfThread->p_sys);
if (!qt_intf)
return;
vlc_LogDestroy(qt_intf->obj.logger);
vlc_object_delete(qt_intf);
testenv->intf = nullptr;
}
//module declaration
vlc_module_begin()
set_callbacks(OpenIntf, CloseIntf)
set_capability("interface", 0)
add_submodule()
set_capability("renderer_discovery", 0)
add_shortcut("rd")
set_callbacks(OpenRD, CloseRD)
add_submodule()
set_capability("renderer probe", 10000)
set_callback(vlc_rd_probe_open)
vlc_module_end()
extern "C" {
const char vlc_module_name[] = MODULE_STRING;
VLC_EXPORT vlc_plugin_cb vlc_static_modules[] = {
VLC_SYMBOL(vlc_entry),
NULL
};
}
VLCTestingEnv::VLCTestingEnv()
{
assert(testenv == nullptr);
testenv = this;
}
VLCTestingEnv::~VLCTestingEnv()
{
libvlc_release(libvlc);
testenv = nullptr;
}
static const char * test_defaults_args[] = {
"-v", "--vout=vdummy", "--aout=adummy", "--text-renderer=tdummy",
};
static const int test_defaults_nargs =
sizeof (test_defaults_args) / sizeof (test_defaults_args[0]);
bool VLCTestingEnv::init()
{
//see test/libvlc/test.h
QByteArray alarm_timeout = qgetenv("VLC_TEST_TIMEOUT");
if (alarm_timeout.isEmpty())
qputenv("QTEST_FUNCTION_TIMEOUT", "5000");
else
qputenv("QTEST_FUNCTION_TIMEOUT", alarm_timeout);
setenv("VLC_PLUGIN_PATH", TOP_BUILDDIR"/modules", 1);
setenv("VLC_LIB_PATH", TOP_BUILDDIR, 1);
libvlc = libvlc_new(test_defaults_nargs, test_defaults_args);
if (!libvlc)
return false;
libvlc_InternalAddIntf(libvlc->p_libvlc_int, MODULE_STRING);
libvlc_InternalPlay(libvlc->p_libvlc_int);
if (!intf)
return false;
return true;
}
/*****************************************************************************
* Copyright (C) 2024 VLC authors and VideoLAN
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef QT_VLC_STUB_MODULES
#define QT_VLC_STUB_MODULES
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <vlc/vlc.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_player.h>
#include <vlc_playlist.h>
#include <vlc_services_discovery.h>
#include <vlc_renderer_discovery.h>
#include <vlc_interface.h>
#include <vlc_cxx_helpers.hpp>
#include "qt.hpp"
#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
#define QCOMPARE_LT(a, b) QVERIFY((a) < (b))
#define QCOMPARE_GT(a, b) QVERIFY((a) > (b))
#define QCOMPARE_LE(a, b) QVERIFY((a) <= (b))
#define QCOMPARE_GE(a, b) QVERIFY((a) >= (b))
#endif
/**
* This class allows to instanciate a libvlc instance with stubbed modules
* the modules instance can be reteived and manipulated using their pointer
* This allows testing models depending on vlc in a controlled environment
* validity of the pointers depends of the module usage
*/
struct VLCTestingEnv
{
VLCTestingEnv();
~VLCTestingEnv();
bool init();
//should be valid after init
libvlc_instance_t* libvlc = nullptr;
//pointer to the qt interface pointer
//no qt related objects are defined in it (no MainCtx, no Compositor ...)
//should be valid after init
qt_intf_t* intf = nullptr;
//render discovery instance (valid once created)
vlc_renderer_discovery_t* renderDiscovery = nullptr;
//if set to false no render discovery will be found
bool renderDiscoveryProbeEnabled = true;
};
#endif /* QT_VLC_STUB_MODULES */