[vlc-commits] [Git][videolan/vlc][master] 4 commits: qt: implement comparison operator in ControlListModel

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Sat Aug 17 08:56:25 UTC 2024



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
6a2a9839 by Fatih Uzunoglu at 2024-08-17T08:44:25+00:00
qt: implement comparison operator in ControlListModel

- - - - -
5adf9db9 by Fatih Uzunoglu at 2024-08-17T08:44:25+00:00
qt: implement comparison operator in PlayerControlbarModel

- - - - -
1a7ac42f by Fatih Uzunoglu at 2024-08-17T08:44:25+00:00
qt: implement comparison operator in ControlbarProfile

- - - - -
749652de by Fatih Uzunoglu at 2024-08-17T08:44:25+00:00
qt: use deep comparison for control bar profile selection

... and promote DEFAULT_STYLE from being a pseudo style
to an actual style.

Addressable types that can not behave like a value type,
such as having an external "ID" field, bring considerable
problems and hinder maintenance. It becomes harder to
serialize which is a necessity since we want to save the
toolbar layout, and new tricky questions arise such as:
are two models that have exactly the same layout and
elements the "same", even if their IDs differ?

This partially reverts commit 09ca278c449b9fac7f90225971c5deb01a354e76,
and uses deep comparison instead of associating ID to the
model for selection purposes.

- - - - -


9 changed files:

- modules/gui/qt/dialogs/firstrun/firstrunwizard.cpp
- modules/gui/qt/dialogs/toolbar/controlbar_profile.cpp
- modules/gui/qt/dialogs/toolbar/controlbar_profile.hpp
- modules/gui/qt/dialogs/toolbar/controlbar_profile_model.cpp
- modules/gui/qt/dialogs/toolbar/controlbar_profile_model.hpp
- modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorDialog.qml
- modules/gui/qt/player/control_list_model.hpp
- modules/gui/qt/player/player_controlbar_model.cpp
- modules/gui/qt/player/player_controlbar_model.hpp


Changes:

=====================================
modules/gui/qt/dialogs/firstrun/firstrunwizard.cpp
=====================================
@@ -141,12 +141,24 @@ void FirstRunWizard::finish()
 
     config_PutInt( "qt-pin-controls", ui.layoutGroup->checkedId() );
 
-    ControlbarProfileModel* controlbarModel = p_intf->p_mi->controlbarProfileModel();
-    assert(controlbarModel);
-    if( ui.layoutGroup->checkedId() )
-        controlbarModel->setSelectedProfileFromId(ControlbarProfileModel::CLASSIC_STYLE);
-    else
-        controlbarModel->setSelectedProfileFromId(ControlbarProfileModel::DEFAULT_STYLE);
+    {
+        ControlbarProfileModel* controlbarModel = p_intf->p_mi->controlbarProfileModel();
+        assert(controlbarModel);
+
+        ControlbarProfileModel::Style style;
+        if( ui.layoutGroup->checkedId() )
+            style = ControlbarProfileModel::Style::CLASSIC_STYLE;
+        else
+            style = ControlbarProfileModel::Style::DEFAULT_STYLE;
+
+        std::unique_ptr<ControlbarProfile> profile( controlbarModel->generateProfileFromStyle( style ) );
+        assert( profile );
+        const std::optional<int> index = controlbarModel->findModel( profile.get() );
+        if( index )
+            controlbarModel->setSelectedProfile( *index );
+        else
+            controlbarModel->insertProfile( std::move( profile ), true );
+    }
 
     /* Commit changes to the scanned folders for the Media Library */
     if( vlc_ml_instance_get( p_intf ) && mlFoldersEditor )
@@ -311,7 +323,6 @@ void FirstRunWizard::reject()
     config_PutInt( "qt-menubar", 0 );
     config_PutInt( "qt-titlebar", 0 );
     p_intf->p_mi->setPinVideoControls( 0 );
-    p_intf->p_mi->controlbarProfileModel()->setSelectedProfileFromId(ControlbarProfileModel::DEFAULT_STYLE);
 
     /* Folders Page settings */
     if ( mlFoldersEditor )


=====================================
modules/gui/qt/dialogs/toolbar/controlbar_profile.cpp
=====================================
@@ -23,85 +23,9 @@
 #include "player/player_controlbar_model.hpp"
 
 
-decltype(ControlbarProfile::m_defaults)
-    ControlbarProfile::m_defaults =
-        {
-            {
-                PlayerControlbarModel::Videoplayer,
-                {
-                    {
-                        {
-                            ControlListModel::LANG_BUTTON,
-                            ControlListModel::BOOKMARK_BUTTON,
-                            ControlListModel::EXTENDED_BUTTON,
-                            ControlListModel::NAVIGATION_BUTTONS
-                        },
-                        {
-                            ControlListModel::SKIP_BACK_BUTTON,
-                            ControlListModel::PREVIOUS_BUTTON,
-                            ControlListModel::PLAY_BUTTON,
-                            ControlListModel::NEXT_BUTTON,
-                            ControlListModel::SKIP_FW_BUTTON
-                        },
-                        {
-                            ControlListModel::VOLUME,
-                            ControlListModel::RENDERER_BUTTON,
-                            ControlListModel::FULLSCREEN_BUTTON
-                        }
-                    }
-                }
-            },
-            {
-                PlayerControlbarModel::Audioplayer,
-                {
-                    {
-                        {
-                            ControlListModel::LANG_BUTTON,
-                            ControlListModel::BOOKMARK_BUTTON,
-                            ControlListModel::EXTENDED_BUTTON
-                        },
-                        {
-                            ControlListModel::RANDOM_BUTTON,
-                            ControlListModel::PREVIOUS_BUTTON,
-                            ControlListModel::PLAY_BUTTON,
-                            ControlListModel::NEXT_BUTTON,
-                            ControlListModel::LOOP_BUTTON
-                        },
-                        {
-                            ControlListModel::VOLUME,
-                            ControlListModel::RENDERER_BUTTON,
-                            ControlListModel::FULLSCREEN_BUTTON
-                        }
-                    }
-                }
-            },
-            {
-                PlayerControlbarModel::Miniplayer,
-                {
-                    {
-                        {
-                            ControlListModel::ARTWORK_INFO
-                        },
-                        {
-                            ControlListModel::RANDOM_BUTTON,
-                            ControlListModel::PREVIOUS_BUTTON,
-                            ControlListModel::PLAY_BUTTON,
-                            ControlListModel::NEXT_BUTTON,
-                            ControlListModel::LOOP_BUTTON
-                        },
-                        {
-                            ControlListModel::VOLUME,
-                            ControlListModel::PLAYER_SWITCH_BUTTON
-                        }
-                    }
-                }
-            }
-        };
-
-
 ControlbarProfile::ControlbarProfile(QObject *parent) : QObject(parent)
 {
-    injectDefaults();
+
 }
 
 PlayerControlbarModel *ControlbarProfile::newModel(int identifier)
@@ -189,16 +113,6 @@ void ControlbarProfile::setName(const QString &name)
     emit nameChanged(m_name);
 }
 
-void ControlbarProfile::setId( const int id )
-{
-    if(id == m_id)
-        return;
-
-    m_id = id;
-
-    emit idChanged(m_id);
-}
-
 bool ControlbarProfile::dirty() const
 {
     return (m_dirty > 0);
@@ -209,17 +123,31 @@ QString ControlbarProfile::name() const
     return m_name;
 }
 
-int ControlbarProfile::id() const
+bool ControlbarProfile::operator==(const ControlbarProfile &model) const
 {
-    return m_id;
-}
+    if (m_models.count() != model.m_models.count())
+        return false;
 
-void ControlbarProfile::injectDefaults(bool resetDirty)
-{
-    injectModel(m_defaults);
+    if (m_models != model.m_models)
+    {
+        // Deep comparison
+        QMapIterator<int, PlayerControlbarModel *> i(m_models);
+        while (i.hasNext())
+        {
+            i.next();
+
+            if (!model.m_models.contains(i.key()))
+                return false;
+
+            assert(model.m_models[i.key()]);
+            assert(i.value());
+
+            if (*model.m_models[i.key()] != *i.value())
+                return false;
+        }
+    }
 
-    if (resetDirty)
-        this->resetDirty(); // defaults normally should not make the profile dirty
+    return true;
 }
 
 void ControlbarProfile::injectModel(const QVector<ControlbarProfile::Configuration> &modelData)


=====================================
modules/gui/qt/dialogs/toolbar/controlbar_profile.hpp
=====================================
@@ -33,7 +33,6 @@ class ControlbarProfile : public QObject
 
     Q_PROPERTY(bool dirty READ dirty RESET resetDirty NOTIFY dirtyChanged FINAL)
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
-    Q_PROPERTY(int profileId READ id WRITE setId NOTIFY idChanged FINAL)
 
     friend class ControlbarProfileModel;
 
@@ -48,21 +47,17 @@ public:
 
     void deleteModel(int identifier);
 
-    Q_INVOKABLE void injectDefaults(bool resetDirty = true);
-
     bool dirty() const;
     QString name() const;
 
-    // The id is a unique number supplied to each profile
-    // which differentiates it independently from its index
-    // in the profiles array. Provides a more stable way to
-    // identify a profile than using its name.
-    int id() const;
+    bool operator==(const ControlbarProfile& model) const;
+    bool operator!=(const ControlbarProfile& model) const {
+        return !(operator==(model));
+    }
 
 public slots:
     void resetDirty();
     void setName(const QString& name);
-    void setId( const int id );
 
 private:
     // m_dirty indicates the count of PlayerControlbarModel
@@ -70,8 +65,7 @@ private:
     // set true.
     int m_dirty = 0;
 
-    int m_id = -1;
-    QString m_name {"N/A"};
+    QString m_name = QStringLiteral("N/A");
     bool m_pauseControlListGeneration = false;
 
     // According to benchmarks, QMap performs better than
@@ -84,7 +78,6 @@ private:
         int identifier;
         std::array<QVector<int>, 3> data;
     };
-    static const QVector<Configuration> m_defaults;
 
 private:
     void injectModel(const QVector<Configuration>& modelData);
@@ -95,7 +88,6 @@ private slots:
 signals:
     void dirtyChanged(bool dirty);
     void nameChanged(QString name);
-    void idChanged(int id);
 
     void controlListChanged(const QVector<int>& linearControlList);
 };


=====================================
modules/gui/qt/dialogs/toolbar/controlbar_profile_model.cpp
=====================================
@@ -29,7 +29,6 @@
 #define SETTINGS_ARRAYNAME_PROFILES "Profiles"
 #define SETTINGS_KEY_NAME "Name"
 #define SETTINGS_KEY_MODEL "Model"
-#define SETTINGS_KEY_ID "Id"
 
 #define SETTINGS_CONTROL_SEPARATOR QChar(',')
 #define SETTINGS_CONFIGURATION_SEPARATOR QChar('|')
@@ -39,7 +38,83 @@ decltype (ControlbarProfileModel::m_defaults)
     ControlbarProfileModel::m_defaults =
         {
             {
-                MINIMALIST_STYLE,
+                Style::DEFAULT_STYLE,
+                N_("Default Style"),
+                {
+                    {
+                        PlayerControlbarModel::Videoplayer,
+                        {
+                            {
+                                {
+                                    ControlListModel::LANG_BUTTON,
+                                    ControlListModel::BOOKMARK_BUTTON,
+                                    ControlListModel::EXTENDED_BUTTON,
+                                    ControlListModel::NAVIGATION_BUTTONS
+                                },
+                                {
+                                    ControlListModel::SKIP_BACK_BUTTON,
+                                    ControlListModel::PREVIOUS_BUTTON,
+                                    ControlListModel::PLAY_BUTTON,
+                                    ControlListModel::NEXT_BUTTON,
+                                    ControlListModel::SKIP_FW_BUTTON
+                                },
+                                {
+                                    ControlListModel::VOLUME,
+                                    ControlListModel::RENDERER_BUTTON,
+                                    ControlListModel::FULLSCREEN_BUTTON
+                                }
+                            }
+                        }
+                    },
+                    {
+                        PlayerControlbarModel::Audioplayer,
+                        {
+                            {
+                                {
+                                    ControlListModel::LANG_BUTTON,
+                                    ControlListModel::BOOKMARK_BUTTON,
+                                    ControlListModel::EXTENDED_BUTTON
+                                },
+                                {
+                                    ControlListModel::RANDOM_BUTTON,
+                                    ControlListModel::PREVIOUS_BUTTON,
+                                    ControlListModel::PLAY_BUTTON,
+                                    ControlListModel::NEXT_BUTTON,
+                                    ControlListModel::LOOP_BUTTON
+                                },
+                                {
+                                    ControlListModel::VOLUME,
+                                    ControlListModel::RENDERER_BUTTON,
+                                    ControlListModel::FULLSCREEN_BUTTON
+                                }
+                            }
+                        }
+                    },
+                    {
+                        PlayerControlbarModel::Miniplayer,
+                        {
+                            {
+                                {
+                                    ControlListModel::ARTWORK_INFO
+                                },
+                                {
+                                    ControlListModel::RANDOM_BUTTON,
+                                    ControlListModel::PREVIOUS_BUTTON,
+                                    ControlListModel::PLAY_BUTTON,
+                                    ControlListModel::NEXT_BUTTON,
+                                    ControlListModel::LOOP_BUTTON
+                                },
+                                {
+                                    ControlListModel::VOLUME,
+                                    ControlListModel::PLAYER_SWITCH_BUTTON
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            {
+                Style::MINIMALIST_STYLE,
                 N_("Minimalist Style"),
                 {
                     {
@@ -107,7 +182,7 @@ decltype (ControlbarProfileModel::m_defaults)
                 }
             },
             {
-                ONE_LINER_STYLE,
+                Style::ONE_LINER_STYLE,
                 N_("One-liner Style"),
                 {
                     {
@@ -185,7 +260,7 @@ decltype (ControlbarProfileModel::m_defaults)
                 }
             },
             {
-                SIMPLEST_STYLE,
+                Style::SIMPLEST_STYLE,
                 N_("Simplest Style"),
                 {
                     {
@@ -242,7 +317,7 @@ decltype (ControlbarProfileModel::m_defaults)
                 }
             },
             {
-                CLASSIC_STYLE,
+                Style::CLASSIC_STYLE,
                 N_("Classic Style"),
                 {
                     {
@@ -359,15 +434,10 @@ ControlbarProfileModel::ControlbarProfileModel(qt_intf_t *p_intf, QObject *paren
 
 void ControlbarProfileModel::insertDefaults()
 {
-    // First, add a blank new profile:
-    // ControlbarProfile will inject the default configurations during its construction.
-    m_maxId = 0;
-    newProfile(tr("Default Profile"), DEFAULT_STYLE);
-
     // Add default profiles:
     for (const auto& i : m_defaults)
     {
-        const auto ptrNewProfile = newProfile(qfut(i.name), i.id);
+        const auto ptrNewProfile = newProfile(qfut(i.name));
         if (!ptrNewProfile)
             continue;
 
@@ -562,18 +632,6 @@ ControlbarProfile* ControlbarProfileModel::currentModel() const
     return getProfile(selectedProfile());
 }
 
-/* Set the selected profile to the profile with the matching id */
-bool ControlbarProfileModel::setSelectedProfileFromId(int id)
-{
-    for(int i = 0; i < rowCount(); i++)
-    {
-        if(id == m_profiles.at(i)->id())
-            return setSelectedProfile(i);
-    }
-
-    return false;
-}
-
 void ControlbarProfileModel::save(bool clearDirty) const
 {
     assert(m_intf);
@@ -633,7 +691,6 @@ void ControlbarProfileModel::save(bool clearDirty) const
 
         settings->setValue(SETTINGS_KEY_NAME, m_profiles.at(i)->name());
         settings->setValue(SETTINGS_KEY_MODEL, val);
-        settings->setValue(SETTINGS_KEY_ID, m_profiles.at(i)->id());
     }
 
     settings->endArray();
@@ -681,7 +738,6 @@ bool ControlbarProfileModel::reload()
 
         const auto ptrNewProfile = new ControlbarProfile(this);
         ptrNewProfile->setName(settings->value(SETTINGS_KEY_NAME).toString());
-        ptrNewProfile->setId(settings->value(SETTINGS_KEY_ID).toInt());
 
         for (auto j : val)
         {
@@ -737,7 +793,6 @@ bool ControlbarProfileModel::reload()
 
     bool ok = false;
     int index = settings->value(SETTINGS_KEY_SELECTEDPROFILE).toInt(&ok);
-    m_maxId = m_profiles.isEmpty() ? 0 : m_profiles.back()->id() + 1;
 
     if (ok)
         setSelectedProfile(index);
@@ -780,6 +835,38 @@ bool ControlbarProfileModel::setSelectedProfile(int selectedProfile)
     return true;
 }
 
+std::optional<int> ControlbarProfileModel::findModel(const ControlbarProfile *profile) const
+{
+    assert(profile);
+    for (int i = 0; i < m_profiles.count(); ++i)
+    {
+        if (m_profiles[i] == profile)
+            return i;
+        else
+        {
+            assert(m_profiles[i]);
+            if (*m_profiles[i] == *profile)
+                return i;
+        }
+    }
+    return std::nullopt;
+}
+
+void ControlbarProfileModel::insertProfile(std::unique_ptr<ControlbarProfile> profile, bool select)
+{
+    assert(profile);
+    const auto ptrProfile = profile.release();
+
+    ptrProfile->setParent(this);
+
+    beginInsertRows(QModelIndex(), m_profiles.size(), m_profiles.size());
+    m_profiles.append(ptrProfile);
+    endInsertRows();
+
+    if (select)
+        setSelectedProfile(m_profiles.count() - 1);
+}
+
 ControlbarProfile *ControlbarProfileModel::getProfile(int index) const
 {
     if (index < 0 || index >= m_profiles.size())
@@ -788,7 +875,7 @@ ControlbarProfile *ControlbarProfileModel::getProfile(int index) const
     return m_profiles.at(index);
 }
 
-ControlbarProfile *ControlbarProfileModel::newProfile(const QString &name, const int id)
+ControlbarProfile *ControlbarProfileModel::newProfile(const QString &name)
 {
     if (name.isEmpty())
         return nullptr;
@@ -796,8 +883,6 @@ ControlbarProfile *ControlbarProfileModel::newProfile(const QString &name, const
     const auto ptrProfile = newProfile();
 
     ptrProfile->setName(generateUniqueName(name));
-    ptrProfile->setId(id);
-    m_maxId++;
 
     return ptrProfile;
 }
@@ -817,8 +902,7 @@ ControlbarProfile *ControlbarProfileModel::newProfile()
 
 ControlbarProfile *ControlbarProfileModel::cloneProfile(const ControlbarProfile *profile)
 {
-    // Any new profiles will just have the next incremental id
-    const auto ptrNewProfile = newProfile(profile->name(), m_maxId);
+    const auto ptrNewProfile = newProfile(profile->name());
 
     if (!ptrNewProfile)
         return nullptr;
@@ -876,3 +960,21 @@ void ControlbarProfileModel::deleteSelectedProfile()
     else
         setSelectedProfile(_selectedProfile);
 }
+
+ControlbarProfile *ControlbarProfileModel::generateProfileFromStyle(const Style style)
+{
+    for (const auto& i : m_defaults)
+    {
+        if (i.id == style)
+        {
+            const auto ptrNewProfile = new ControlbarProfile();
+            ptrNewProfile->injectModel(i.modelData);
+            ptrNewProfile->setName(i.name);
+            ptrNewProfile->resetDirty(); // default profiles should not be dirty initially
+            return ptrNewProfile;
+        }
+    }
+
+    // Style does not exist
+    return nullptr;
+}


=====================================
modules/gui/qt/dialogs/toolbar/controlbar_profile_model.hpp
=====================================
@@ -42,7 +42,15 @@ public:
     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
 
     QHash<int, QByteArray> roleNames() const override;
-    enum {DEFAULT_STYLE, MINIMALIST_STYLE, ONE_LINER_STYLE, SIMPLEST_STYLE, CLASSIC_STYLE};
+
+    enum class Style
+    {
+        DEFAULT_STYLE,
+        MINIMALIST_STYLE,
+        ONE_LINER_STYLE,
+        SIMPLEST_STYLE,
+        CLASSIC_STYLE
+    };
 
     // Editable:
     Q_INVOKABLE bool setData(const QModelIndex &index, const QVariant &value,
@@ -63,24 +71,32 @@ public:
 
     int selectedProfile() const;
     ControlbarProfile* currentModel() const;
-    bool setSelectedProfileFromId(int id);
 
     ControlbarProfile* cloneProfile(const ControlbarProfile* profile);
     Q_INVOKABLE void cloneSelectedProfile(const QString& newProfileName);
 
     Q_INVOKABLE ControlbarProfile* getProfile(int index) const;
 
-    Q_INVOKABLE ControlbarProfile* newProfile(const QString& name, const int id);
+    Q_INVOKABLE ControlbarProfile* newProfile(const QString& name);
     ControlbarProfile* newProfile();
 
     Q_INVOKABLE void deleteSelectedProfile();
 
+    // This is a static method, caller takes the ownership
+    // of the profile:
+    static ControlbarProfile* generateProfileFromStyle(const Style style);
+
+    // ControlbarProfileModel takes the ownership:
+    void insertProfile(std::unique_ptr<ControlbarProfile> profile, bool select);
+
 public slots:
     void save(bool clearDirty = true) const;
     bool reload();
 
     bool setSelectedProfile(int selectedProfile);
 
+    std::optional<int> findModel(const ControlbarProfile* profile) const;
+
 signals:
     void countChanged();
     void selectedProfileChanged();
@@ -91,10 +107,9 @@ private:
     QVector<ControlbarProfile *> m_profiles;
 
     int m_selectedProfile = -1;
-    int m_maxId = 0;
 
     struct Profile {
-        const int id;
+        const Style id;
         const char* name;
         QVector<ControlbarProfile::Configuration> modelData;
     };


=====================================
modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorDialog.qml
=====================================
@@ -157,17 +157,6 @@ WindowDialog {
                     }
                 }
 
-                Widgets.IconToolButton {
-                    id: useDefaultButton
-
-                    description: qsTr("Use Default")
-                    text: VLCIcons.history
-
-                    onClicked: {
-                        MainCtx.controlbarProfileModel.currentModel.injectDefaults(false)
-                    }
-                }
-
                 Widgets.IconToolButton {
                     description: qsTr("Delete the current profile")
                     text: VLCIcons.del


=====================================
modules/gui/qt/player/control_list_model.hpp
=====================================
@@ -102,6 +102,16 @@ public:
     QVector<int> getControls() const;
     void setControls(const QVector<int>& list);
 
+    bool operator==(const ControlListModel& model) const
+    {
+        return m_controls == model.m_controls;
+    }
+
+    bool operator!=(const ControlListModel& model) const
+    {
+        return !(operator==(model));
+    }
+
 signals:
     void countChanged();
 


=====================================
modules/gui/qt/player/player_controlbar_model.cpp
=====================================
@@ -126,6 +126,26 @@ ControlListModel *PlayerControlbarModel::right() const
     return m_right;
 }
 
+bool PlayerControlbarModel::operator==(const PlayerControlbarModel &model) const
+{
+    assert(m_left && model.m_left);
+    assert(m_center && model.m_center);
+    assert(m_right && model.m_right);
+
+    // Deep comparison
+
+    if (*m_left != *model.m_left)
+        return false;
+
+    if (*m_center != *model.m_center)
+        return false;
+
+    if (*m_right != *model.m_right)
+        return false;
+
+    return true;
+}
+
 void PlayerControlbarModel::setDirty(bool dirty)
 {
     if (m_dirty == dirty)


=====================================
modules/gui/qt/player/player_controlbar_model.hpp
=====================================
@@ -80,6 +80,11 @@ public:
     ControlListModel* center() const;
     ControlListModel* right() const;
 
+    bool operator==(const PlayerControlbarModel& model) const;
+    bool operator!=(const PlayerControlbarModel& model) const {
+        return !(operator==(model));
+    }
+
 public slots:
     void setDirty(bool dirty);
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e61bab777f0f063575e63cb78de981697576192b...749652de64eafe61b5836b782a39c139404c1c19

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e61bab777f0f063575e63cb78de981697576192b...749652de64eafe61b5836b782a39c139404c1c19
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list