aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kodi.xcodeproj/project.pbxproj6
-rw-r--r--project/VS2010Express/XBMC.vcxproj3
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters9
-rw-r--r--xbmc/addons/AddonEvents.h53
-rw-r--r--xbmc/addons/AddonInstaller.cpp17
-rw-r--r--xbmc/addons/AddonManager.cpp60
-rw-r--r--xbmc/addons/AddonManager.h23
-rw-r--r--xbmc/addons/BinaryAddonCache.cpp9
-rw-r--r--xbmc/addons/BinaryAddonCache.h5
-rw-r--r--xbmc/addons/CMakeLists.txt1
-rw-r--r--xbmc/addons/GUIDialogAddonInfo.cpp1
-rw-r--r--xbmc/addons/GUIWindowAddonBrowser.cpp17
-rw-r--r--xbmc/addons/GUIWindowAddonBrowser.h10
-rw-r--r--xbmc/addons/RepositoryUpdater.cpp4
-rw-r--r--xbmc/addons/RepositoryUpdater.h8
-rw-r--r--xbmc/games/controllers/windows/GUIControllerList.cpp12
-rw-r--r--xbmc/games/controllers/windows/GUIControllerList.h9
-rw-r--r--xbmc/games/controllers/windows/GUIControllerWindow.cpp12
-rw-r--r--xbmc/games/controllers/windows/GUIControllerWindow.h9
-rw-r--r--xbmc/interfaces/builtins/AddonBuiltins.cpp2
-rw-r--r--xbmc/listproviders/DirectoryProvider.cpp48
-rw-r--r--xbmc/listproviders/DirectoryProvider.h5
-rw-r--r--xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp8
-rw-r--r--xbmc/peripherals/bus/virtual/PeripheralBusAddon.h7
-rw-r--r--xbmc/utils/CMakeLists.txt2
-rw-r--r--xbmc/utils/EventStream.h90
-rw-r--r--xbmc/utils/EventStreamDetail.h80
-rw-r--r--xbmc/windows/GUIMediaWindow.cpp20
28 files changed, 412 insertions, 118 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index fee595be33..b9356802a6 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -2577,6 +2577,9 @@
2A4AAD251CEBC2060057AD44 /* DVDDemuxVobsub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVDDemuxVobsub.h; sourceTree = "<group>"; };
2A4AAD261CEBC2130057AD44 /* DVDFactoryDemuxer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVDFactoryDemuxer.h; sourceTree = "<group>"; };
2A4AAD281CEBC64A0057AD44 /* GUIInfoLabels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIInfoLabels.h; sourceTree = "<group>"; };
+ 2A5531F81D4A0F9C00BDCE99 /* AddonEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddonEvents.h; sourceTree = "<group>"; };
+ 2A5531F91D4A0FEB00BDCE99 /* EventStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventStream.h; sourceTree = "<group>"; };
+ 2A5531FA1D4A0FEB00BDCE99 /* EventStreamDetail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventStreamDetail.h; sourceTree = "<group>"; };
2A7B2BDB1BD6F16600044BCD /* PVRSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PVRSettings.cpp; sourceTree = "<group>"; };
2A7B2BDE1BD6F18B00044BCD /* PVRSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRSettings.h; sourceTree = "<group>"; };
2A7E24C71CEBBC3B003096EB /* libKODI_peripheral.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libKODI_peripheral.h; path = "kodi-addon-dev-kit/include/kodi/libKODI_peripheral.h"; sourceTree = "<group>"; };
@@ -5117,6 +5120,7 @@
18B7C3821294203F009E7A26 /* AddonDatabase.cpp */,
18B7C3831294203F009E7A26 /* AddonDatabase.h */,
18B49FF31152BFA5001AF8A6 /* AddonDll.h */,
+ 2A5531F81D4A0F9C00BDCE99 /* AddonEvents.h */,
7C4705AC12EF584C00369E51 /* AddonInstaller.cpp */,
7C4705AD12EF584C00369E51 /* AddonInstaller.h */,
18B49FF41152BFA5001AF8A6 /* AddonManager.cpp */,
@@ -8699,6 +8703,8 @@
436B38F3106628850049AB3B /* EndianSwap.h */,
DF529BAC1741697B00523FB4 /* Environment.cpp */,
DF529BAD1741697B00523FB4 /* Environment.h */,
+ 2A5531F91D4A0FEB00BDCE99 /* EventStream.h */,
+ 2A5531FA1D4A0FEB00BDCE99 /* EventStreamDetail.h */,
E36C29E90DA72486001F0C9D /* Fanart.cpp */,
6E97BDC30DA2B620003A2A89 /* Fanart.h */,
F5F244641110DC6B009126C6 /* FileOperationJob.cpp */,
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index 8667a55212..3efccee4c2 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -2331,6 +2331,8 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command>
<ClInclude Include="..\..\xbmc\utils\Crc32.h" />
<ClInclude Include="..\..\xbmc\utils\DatabaseUtils.h" />
<ClInclude Include="..\..\xbmc\utils\EndianSwap.h" />
+ <ClInclude Include="..\..\xbmc\utils\EventStream.h" />
+ <ClInclude Include="..\..\xbmc\utils\EventStreamDetail.h" />
<ClInclude Include="..\..\xbmc\utils\Fanart.h" />
<ClInclude Include="..\..\xbmc\utils\FileOperationJob.h" />
<ClInclude Include="..\..\xbmc\utils\FileUtils.h" />
@@ -2564,6 +2566,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command>
<ClInclude Include="..\..\xbmc\FileSystem\VideoDatabaseDirectory\QueryParams.h" />
<ClInclude Include="..\..\xbmc\addons\Addon.h" />
<ClInclude Include="..\..\xbmc\addons\AddonDll.h" />
+ <ClInclude Include="..\..\xbmc\addons\AddonEvents.h" />
<ClInclude Include="..\..\xbmc\addons\AddonManager.h" />
<ClInclude Include="..\..\xbmc\addons\AddonStatusHandler.h" />
<ClInclude Include="..\..\xbmc\addons\AudioEncoder.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 595e123080..a8ecdd48be 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -3868,6 +3868,9 @@
<ClInclude Include="..\..\xbmc\addons\AddonDll.h">
<Filter>addons</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\addons\AddonEvents.h">
+ <Filter>addons</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\addons\AddonManager.h">
<Filter>addons</Filter>
</ClInclude>
@@ -4545,6 +4548,12 @@
<ClInclude Include="..\..\xbmc\utils\EndianSwap.h">
<Filter>utils</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\utils\EventStream.h">
+ <Filter>utils</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\utils\EventStreamDetail.h">
+ <Filter>utils</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\utils\Fanart.h">
<Filter>utils</Filter>
</ClInclude>
diff --git a/xbmc/addons/AddonEvents.h b/xbmc/addons/AddonEvents.h
new file mode 100644
index 0000000000..04b8693b07
--- /dev/null
+++ b/xbmc/addons/AddonEvents.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Team Kodi
+ * http://kodi.tv
+ *
+ * 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, 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 XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <string>
+
+namespace ADDON
+{
+ struct AddonEvent
+ {
+ virtual ~AddonEvent() {};
+ };
+
+ namespace AddonEvents
+ {
+ struct Enabled : AddonEvent
+ {
+ std::string id;
+ Enabled(std::string id) : id(std::move(id)) {}
+ };
+
+ struct Disabled : AddonEvent
+ {
+ std::string id;
+ Disabled(std::string id) : id(std::move(id)) {}
+ };
+
+ struct MetadataChanged : AddonEvent
+ {
+ std::string id;
+ MetadataChanged(std::string id) : id(std::move(id)) {}
+ };
+
+ struct InstalledChanged : AddonEvent {};
+ };
+};
diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp
index 9ecbbdb2c7..5fb65055a0 100644
--- a/xbmc/addons/AddonInstaller.cpp
+++ b/xbmc/addons/AddonInstaller.cpp
@@ -601,10 +601,7 @@ bool CAddonInstallJob::DoWork()
if (!Install(installFrom, m_repo))
return false;
- CAddonMgr::GetInstance().UnregisterAddon(m_addon->ID());
- CAddonMgr::GetInstance().FindAddons();
-
- if (!CAddonMgr::GetInstance().GetAddon(m_addon->ID(), m_addon, ADDON_UNKNOWN, false))
+ if (!CAddonMgr::GetInstance().ReloadAddon(m_addon))
{
CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to reload addon", m_addon->ID().c_str());
return false;
@@ -615,9 +612,6 @@ bool CAddonInstallJob::DoWork()
ADDON::OnPostInstall(m_addon, m_update, IsModal());
- //Enable it if it was previously disabled
- CAddonMgr::GetInstance().EnableAddon(m_addon->ID());
-
{
CAddonDatabase database;
database.Open();
@@ -626,9 +620,6 @@ bool CAddonInstallJob::DoWork()
database.SetLastUpdated(m_addon->ID(), CDateTime::GetCurrentDateTime());
}
- // notify any observers that add-ons have changed
- CAddonMgr::GetInstance().NotifyObservers(ObservableMessageAddons);
-
CEventLog::GetInstance().Add(
EventPtr(new CAddonManagementEvent(m_addon, m_update ? 24065 : 24064)),
!IsModal() && CSettings::GetInstance().GetBool(CSettings::SETTING_ADDONS_NOTIFICATIONS), false);
@@ -854,7 +845,11 @@ bool CAddonUnInstallJob::DoWork()
//Unregister addon with the manager to ensure nothing tries
//to interact with it while we are uninstalling.
- CAddonMgr::GetInstance().UnregisterAddon(m_addon->ID());
+ if (!CAddonMgr::GetInstance().UnloadAddon(m_addon))
+ {
+ CLog::Log(LOGERROR, "CAddonUnInstallJob[%s]: failed to unload addon.", m_addon->ID().c_str());
+ return false;
+ }
if (!DeleteAddon(m_addon->Path()))
{
diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp
index 4bad98d466..ee9ad79c2e 100644
--- a/xbmc/addons/AddonManager.cpp
+++ b/xbmc/addons/AddonManager.cpp
@@ -357,7 +357,7 @@ bool CAddonMgr::Init()
if (!m_database.Open())
CLog::Log(LOGFATAL, "ADDONS: Failed to open database");
- FindAddonsAndNotify();
+ FindAddons();
//Ensure required add-ons are installed and enabled
for (const auto& id : m_systemAddons)
@@ -723,32 +723,36 @@ bool CAddonMgr::FindAddons()
m_database.GetBlacklisted(tmp);
m_updateBlacklist = std::move(tmp);
- SetChanged();
+ m_events.Publish(AddonEvents::InstalledChanged());
}
return result;
}
-bool CAddonMgr::FindAddonsAndNotify()
-{
- if (!FindAddons())
- return false;
-
- NotifyObservers(ObservableMessageAddons);
-
- return true;
-}
-
-void CAddonMgr::UnregisterAddon(const std::string& ID)
+bool CAddonMgr::UnloadAddon(const AddonPtr& addon)
{
CSingleLock lock(m_critSection);
if (m_cpluff && m_cp_context)
{
- m_cpluff->uninstall_plugin(m_cp_context, ID.c_str());
- SetChanged();
- lock.Leave();
- NotifyObservers(ObservableMessageAddons);
+ if (m_cpluff->uninstall_plugin(m_cp_context, addon->ID().c_str()) == CP_OK)
+ {
+ m_events.Publish(AddonEvents::InstalledChanged());
+ return true;
+ }
}
+ return false;
+}
+
+bool CAddonMgr::ReloadAddon(AddonPtr& addon)
+{
+ CSingleLock lock(m_critSection);
+ if (!addon ||!m_cpluff || !m_cp_context)
+ return false;
+
+ m_cpluff->uninstall_plugin(m_cp_context, addon->ID().c_str());
+ return FindAddons()
+ && GetAddon(addon->ID(), addon, ADDON_UNKNOWN, false)
+ && EnableAddon(addon->ID());
}
void CAddonMgr::OnPostUnInstall(const std::string& id)
@@ -780,6 +784,18 @@ bool CAddonMgr::IsBlacklisted(const std::string& id) const
return m_updateBlacklist.find(id) != m_updateBlacklist.end();
}
+void CAddonMgr::UpdateLastUsed(const std::string& id)
+{
+ auto time = CDateTime::GetCurrentDateTime();
+ CJobManager::GetInstance().Submit([this, id, time](){
+ {
+ CSingleLock lock(m_critSection);
+ m_database.SetLastUsed(id, time);
+ }
+ m_events.Publish(AddonEvents::MetadataChanged(id));
+ });
+}
+
static void ResolveDependencies(const std::string& addonId, std::vector<std::string>& needed, std::vector<std::string>& missing)
{
if (std::find(needed.begin(), needed.end(), addonId) != needed.end())
@@ -809,12 +825,14 @@ bool CAddonMgr::DisableAddon(const std::string& id)
if (!m_disabled.insert(id).second)
return false;
+ //success
+ ADDON::OnDisabled(id);
+
AddonPtr addon;
if (GetAddon(id, addon, ADDON_UNKNOWN, false) && addon != NULL)
CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24141)));
- //success
- ADDON::OnDisabled(id);
+ m_events.Publish(AddonEvents::Disabled(id));
return true;
}
@@ -833,11 +851,14 @@ bool CAddonMgr::EnableSingle(const std::string& id)
CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24064)));
CLog::Log(LOGDEBUG, "CAddonMgr: enabled %s", addon->ID().c_str());
+ m_events.Publish(AddonEvents::Enabled(id));
return true;
}
bool CAddonMgr::EnableAddon(const std::string& id)
{
+ if (id.empty() || !IsAddonInstalled(id))
+ return false;
std::vector<std::string> needed;
std::vector<std::string> missing;
ResolveDependencies(id, needed, missing);
@@ -846,6 +867,7 @@ bool CAddonMgr::EnableAddon(const std::string& id)
"correctly", dep.c_str(), id.c_str());
for (auto it = needed.rbegin(); it != needed.rend(); ++it)
EnableSingle(*it);
+
return true;
}
diff --git a/xbmc/addons/AddonManager.h b/xbmc/addons/AddonManager.h
index 969de5e9f7..7a2835cc56 100644
--- a/xbmc/addons/AddonManager.h
+++ b/xbmc/addons/AddonManager.h
@@ -19,14 +19,16 @@
*
*/
#include "Addon.h"
+#include "AddonDatabase.h"
+#include "AddonEvents.h"
+#include "Repository.h"
#include "threads/CriticalSection.h"
-#include "utils/Observer.h"
+#include "utils/EventStream.h"
#include <string>
#include <vector>
#include <map>
#include <deque>
-#include "AddonDatabase.h"
-#include "Repository.h"
+
class DllLibCPluff;
extern "C"
@@ -62,7 +64,7 @@ namespace ADDON
* otherwise. Services the generic callbacks available
* to all addon variants.
*/
- class CAddonMgr : public Observable
+ class CAddonMgr
{
public:
static CAddonMgr &GetInstance();
@@ -75,6 +77,7 @@ namespace ADDON
CAddonMgr const& operator=(CAddonMgr const&);
virtual ~CAddonMgr();
+ CEventStream<AddonEvent>& Events() { return m_events; }
IAddonMgrCallback* GetCallbackForType(TYPE type);
bool RegisterAddonMgrCallback(TYPE type, IAddonMgrCallback* cb);
@@ -135,12 +138,11 @@ namespace ADDON
*/
bool FindAddons();
- /*! \brief Checks for new / updated add-ons and notifies all observers
- \return True if everything went ok, false otherwise
- */
- bool FindAddonsAndNotify();
+ /*! Unload addon from the system. Returns true if it was unloaded, otherwise false. */
+ bool UnloadAddon(const AddonPtr& addon);
- void UnregisterAddon(const std::string& ID);
+ /*! Returns true if the addon was successfully loaded and enabled; otherwise false. */
+ bool ReloadAddon(AddonPtr& addon);
/*! Hook for clearing internal state after uninstall. */
void OnPostUnInstall(const std::string& id);
@@ -182,6 +184,8 @@ namespace ADDON
bool RemoveFromUpdateBlacklist(const std::string& id);
bool IsBlacklisted(const std::string& id) const;
+ void UpdateLastUsed(const std::string& id);
+
/* libcpluff */
std::string GetExtValue(cp_cfg_element_t *base, const char *path) const;
@@ -266,6 +270,7 @@ namespace ADDON
static std::map<TYPE, IAddonMgrCallback*> m_managers;
CCriticalSection m_critSection;
CAddonDatabase m_database;
+ CEventSource<AddonEvent> m_events;
std::set<std::string> m_systemAddons;
std::set<std::string> m_optionalAddons;
};
diff --git a/xbmc/addons/BinaryAddonCache.cpp b/xbmc/addons/BinaryAddonCache.cpp
index c2caa5e88a..0c3a2b708b 100644
--- a/xbmc/addons/BinaryAddonCache.cpp
+++ b/xbmc/addons/BinaryAddonCache.cpp
@@ -33,13 +33,13 @@ CBinaryAddonCache::~CBinaryAddonCache()
void CBinaryAddonCache::Init()
{
m_addonsToCache = {ADDON_AUDIODECODER, ADDON_INPUTSTREAM};
- CAddonMgr::GetInstance().RegisterObserver(this);
+ CAddonMgr::GetInstance().Events().Subscribe(this, &CBinaryAddonCache::OnEvent);
Update();
}
void CBinaryAddonCache::Deinit()
{
- CAddonMgr::GetInstance().UnregisterObserver(this);
+ CAddonMgr::GetInstance().Events().Unsubscribe(this);
}
void CBinaryAddonCache::GetAddons(VECADDONS& addons, const TYPE& type)
@@ -57,9 +57,10 @@ void CBinaryAddonCache::GetAddons(VECADDONS& addons, const TYPE& type)
}
}
-void CBinaryAddonCache::Notify(const Observable &obs, const ObservableMessage msg)
+void CBinaryAddonCache::OnEvent(const AddonEvent& event)
{
- Update();
+ if (typeid(event) == typeid(AddonEvents::InstalledChanged))
+ Update();
}
void CBinaryAddonCache::Update()
diff --git a/xbmc/addons/BinaryAddonCache.h b/xbmc/addons/BinaryAddonCache.h
index 164288522f..970069725c 100644
--- a/xbmc/addons/BinaryAddonCache.h
+++ b/xbmc/addons/BinaryAddonCache.h
@@ -22,23 +22,24 @@
#include "utils/Observer.h"
#include "Addon.h"
+#include "AddonEvents.h"
#include "threads/CriticalSection.h"
#include <map>
#include <vector>
namespace ADDON {
-class CBinaryAddonCache : public Observer
+class CBinaryAddonCache
{
public:
virtual ~CBinaryAddonCache();
void Init();
void Deinit();
void GetAddons(VECADDONS& addons, const TYPE& type);
- virtual void Notify(const Observable &obs, const ObservableMessage msg) override;
protected:
void Update();
+ void OnEvent(const AddonEvent& event);
CCriticalSection m_critSection;
std::multimap<TYPE, VECADDONS> m_addons;
diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt
index af1ee00f84..cb4da8cbd7 100644
--- a/xbmc/addons/CMakeLists.txt
+++ b/xbmc/addons/CMakeLists.txt
@@ -32,6 +32,7 @@ set(SOURCES Addon.cpp
set(HEADERS Addon.h
AddonBuilder.h
+ AddonEvents.h
BinaryAddonCache.h
AddonDatabase.h
AddonDll.h
diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp
index e6c23b080e..81f1104a06 100644
--- a/xbmc/addons/GUIDialogAddonInfo.cpp
+++ b/xbmc/addons/GUIDialogAddonInfo.cpp
@@ -457,7 +457,6 @@ void CGUIDialogAddonInfo::OnEnableDisable()
CAddonMgr::GetInstance().EnableAddon(m_localAddon->ID());
UpdateControls();
- g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
}
void CGUIDialogAddonInfo::OnSettings()
diff --git a/xbmc/addons/GUIWindowAddonBrowser.cpp b/xbmc/addons/GUIWindowAddonBrowser.cpp
index a79b404cb6..b2909d766a 100644
--- a/xbmc/addons/GUIWindowAddonBrowser.cpp
+++ b/xbmc/addons/GUIWindowAddonBrowser.cpp
@@ -71,12 +71,18 @@ bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message)
{
case GUI_MSG_WINDOW_DEINIT:
{
+ CRepositoryUpdater::GetInstance().Events().Unsubscribe(this);
+ CAddonMgr::GetInstance().Events().Unsubscribe(this);
+
if (m_thumbLoader.IsLoading())
m_thumbLoader.StopThread();
}
break;
case GUI_MSG_WINDOW_INIT:
{
+ CRepositoryUpdater::GetInstance().Events().Subscribe(this, &CGUIWindowAddonBrowser::OnEvent);
+ CAddonMgr::GetInstance().Events().Subscribe(this, &CGUIWindowAddonBrowser::OnEvent);
+
SetProperties();
}
break;
@@ -163,6 +169,17 @@ class UpdateAddons : public IRunnable
}
};
+void CGUIWindowAddonBrowser::OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated& event)
+{
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
+ g_windowManager.SendThreadMessage(msg);
+}
+
+void CGUIWindowAddonBrowser::OnEvent(const ADDON::AddonEvent& event)
+{
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
+ g_windowManager.SendThreadMessage(msg);
+}
bool CGUIWindowAddonBrowser::OnClick(int iItem, const std::string &player)
{
diff --git a/xbmc/addons/GUIWindowAddonBrowser.h b/xbmc/addons/GUIWindowAddonBrowser.h
index 0831fd9dd1..b1c7822cb3 100644
--- a/xbmc/addons/GUIWindowAddonBrowser.h
+++ b/xbmc/addons/GUIWindowAddonBrowser.h
@@ -22,10 +22,12 @@
#include <string>
#include <vector>
-
-#include "addons/Addon.h"
-#include "windows/GUIMediaWindow.h"
+#include "Addon.h"
+#include "AddonEvents.h"
+#include "RepositoryUpdater.h"
#include "ThumbLoader.h"
+#include "windows/GUIMediaWindow.h"
+
class CFileItem;
class CFileItemList;
@@ -75,6 +77,8 @@ protected:
private:
void SetProperties();
void UpdateStatus(const CFileItemPtr& item);
+ void OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated& event);
+ void OnEvent(const ADDON::AddonEvent& event);
CProgramThumbLoader m_thumbLoader;
};
diff --git a/xbmc/addons/RepositoryUpdater.cpp b/xbmc/addons/RepositoryUpdater.cpp
index 719f8840fc..41bc15c496 100644
--- a/xbmc/addons/RepositoryUpdater.cpp
+++ b/xbmc/addons/RepositoryUpdater.cpp
@@ -20,7 +20,6 @@
#include "RepositoryUpdater.h"
#include "Application.h"
-#include "GUIUserMessages.h"
#include "addons/AddonInstaller.h"
#include "addons/AddonManager.h"
#include "addons/AddonSystemSettings.h"
@@ -89,8 +88,7 @@ void CRepositoryUpdater::OnJobComplete(unsigned int jobID, bool success, CJob* j
ScheduleUpdate();
- CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
- g_windowManager.SendThreadMessage(msg);
+ m_events.Publish(RepositoryUpdated{});
}
}
diff --git a/xbmc/addons/RepositoryUpdater.h b/xbmc/addons/RepositoryUpdater.h
index 80afc9133f..9075df185a 100644
--- a/xbmc/addons/RepositoryUpdater.h
+++ b/xbmc/addons/RepositoryUpdater.h
@@ -23,6 +23,7 @@
#include "dialogs/GUIDialogExtendedProgressBar.h"
#include "threads/CriticalSection.h"
#include "threads/Timer.h"
+#include "utils/EventStream.h"
#include "XBDateTime.h"
#include <vector>
@@ -65,8 +66,13 @@ public:
*/
CDateTime LastUpdated() const;
+
virtual void OnSettingChanged(const CSetting* setting) override;
+ struct RepositoryUpdated { };
+
+ CEventStream<RepositoryUpdated>& Events() { return m_events; }
+
private:
CRepositoryUpdater();
CRepositoryUpdater(const CRepositoryUpdater&) = delete;
@@ -82,5 +88,7 @@ private:
CTimer m_timer;
CEvent m_doneEvent;
std::vector<CRepositoryUpdateJob*> m_jobs;
+
+ CEventSource<RepositoryUpdated> m_events;
};
}
diff --git a/xbmc/games/controllers/windows/GUIControllerList.cpp b/xbmc/games/controllers/windows/GUIControllerList.cpp
index 3a088a6bfa..1fabf9b354 100644
--- a/xbmc/games/controllers/windows/GUIControllerList.cpp
+++ b/xbmc/games/controllers/windows/GUIControllerList.cpp
@@ -61,17 +61,16 @@ bool CGUIControllerList::Initialize(void)
if (m_controllerButton)
m_controllerButton->SetVisible(false);
+ CAddonMgr::GetInstance().Events().Subscribe(this, &CGUIControllerList::OnEvent);
Refresh();
- CAddonMgr::GetInstance().RegisterObserver(this);
-
return m_controllerList != nullptr &&
m_controllerButton != nullptr;
}
void CGUIControllerList::Deinitialize(void)
{
- CAddonMgr::GetInstance().UnregisterObserver(this);
+ CAddonMgr::GetInstance().Events().Unsubscribe(this);
CleanupButtons();
@@ -143,12 +142,11 @@ void CGUIControllerList::ResetController(void)
}
}
-void CGUIControllerList::Notify(const Observable& obs, const ObservableMessage msg)
+void CGUIControllerList::OnEvent(const ADDON::AddonEvent& event)
{
- using namespace KODI::MESSAGING;
-
- if (msg == ObservableMessageAddons)
+ if (typeid(event) == typeid(ADDON::AddonEvents::InstalledChanged))
{
+ using namespace KODI::MESSAGING;
CGUIMessage msg(GUI_MSG_REFRESH_LIST, m_guiWindow->GetID(), CONTROL_CONTROLLER_LIST);
CApplicationMessenger::GetInstance().SendGUIMessage(msg);
}
diff --git a/xbmc/games/controllers/windows/GUIControllerList.h b/xbmc/games/controllers/windows/GUIControllerList.h
index 44197d50bf..036cea9576 100644
--- a/xbmc/games/controllers/windows/GUIControllerList.h
+++ b/xbmc/games/controllers/windows/GUIControllerList.h
@@ -20,9 +20,9 @@
#pragma once
#include "IConfigurationWindow.h"
+#include "addons/AddonEvents.h"
#include "addons/Addon.h"
#include "games/controllers/ControllerTypes.h"
-#include "utils/Observer.h"
#include <set>
#include <string>
@@ -35,8 +35,7 @@ namespace GAME
{
class CGUIControllerWindow;
- class CGUIControllerList : public IControllerList,
- public Observer
+ class CGUIControllerList : public IControllerList
{
public:
CGUIControllerList(CGUIWindow* window, IFeatureList* featureList);
@@ -50,9 +49,6 @@ namespace GAME
virtual void OnSelect(unsigned int controllerIndex) override;
virtual void ResetController(void) override;
- // implementation of Observer
- virtual void Notify(const Observable& obs, const ObservableMessage msg) override;
-
private:
bool RefreshControllers(void);
@@ -63,6 +59,7 @@ namespace GAME
void UnregisterController(const std::string& controllerId);
void CleanupButtons(void);
+ void OnEvent(const ADDON::AddonEvent& event);
// GUI stuff
CGUIWindow* const m_guiWindow;
diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.cpp b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
index 65bb09f3c8..b8f52a6e48 100644
--- a/xbmc/games/controllers/windows/GUIControllerWindow.cpp
+++ b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
@@ -151,10 +151,9 @@ bool CGUIControllerWindow::OnMessage(CGUIMessage& message)
return CGUIDialog::OnMessage(message);
}
-void CGUIControllerWindow::Notify(const Observable &obs, const ObservableMessage msg)
+void CGUIControllerWindow::OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated& event)
{
- if (msg == ObservableMessageAddons)
- UpdateButtons();
+ UpdateButtons();
}
void CGUIControllerWindow::OnInitWindow(void)
@@ -205,14 +204,15 @@ void CGUIControllerWindow::OnInitWindow(void)
Close();
}
- UpdateButtons();
+ // FIXME: not thread safe
+// ADDON::CRepositoryUpdater::GetInstance().Events().Subscribe(this, &CGUIControllerWindow::OnEvent);
- ADDON::CAddonMgr::GetInstance().RegisterObserver(this);
+ UpdateButtons();
}
void CGUIControllerWindow::OnDeinitWindow(int nextWindowID)
{
- ADDON::CAddonMgr::GetInstance().UnregisterObserver(this);
+ ADDON::CRepositoryUpdater::GetInstance().Events().Unsubscribe(this);
if (m_controllerList)
{
diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.h b/xbmc/games/controllers/windows/GUIControllerWindow.h
index ca8c442753..835068bac3 100644
--- a/xbmc/games/controllers/windows/GUIControllerWindow.h
+++ b/xbmc/games/controllers/windows/GUIControllerWindow.h
@@ -19,6 +19,7 @@
*/
#pragma once
+#include "addons/RepositoryUpdater.h"
#include "guilib/GUIDialog.h"
#include "utils/Observer.h"
@@ -27,8 +28,7 @@ namespace GAME
class IControllerList;
class IFeatureList;
- class CGUIControllerWindow : public CGUIDialog,
- public Observer
+ class CGUIControllerWindow : public CGUIDialog
{
public:
CGUIControllerWindow(void);
@@ -37,9 +37,6 @@ namespace GAME
// implementation of CGUIControl via CGUIDialog
virtual bool OnMessage(CGUIMessage& message) override;
- // implementation of Observer
- void Notify(const Observable &obs, const ObservableMessage msg) override;
-
protected:
// implementation of CGUIWindow via CGUIDialog
virtual void OnInitWindow(void) override;
@@ -50,7 +47,7 @@ namespace GAME
void OnControllerSelected(unsigned int controllerIndex);
void OnFeatureFocused(unsigned int featureIndex);
void OnFeatureSelected(unsigned int featureIndex);
-
+ void OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated& event);
void UpdateButtons(void);
// Action for the available button
diff --git a/xbmc/interfaces/builtins/AddonBuiltins.cpp b/xbmc/interfaces/builtins/AddonBuiltins.cpp
index 446fc97886..18b112dd2d 100644
--- a/xbmc/interfaces/builtins/AddonBuiltins.cpp
+++ b/xbmc/interfaces/builtins/AddonBuiltins.cpp
@@ -302,7 +302,7 @@ static int UpdateRepos(const std::vector<std::string>& params)
*/
static int UpdateLocals(const std::vector<std::string>& params)
{
- CAddonMgr::GetInstance().FindAddonsAndNotify();
+ CAddonMgr::GetInstance().FindAddons();
return 0;
}
diff --git a/xbmc/listproviders/DirectoryProvider.cpp b/xbmc/listproviders/DirectoryProvider.cpp
index a13e65e120..d01d6fa07d 100644
--- a/xbmc/listproviders/DirectoryProvider.cpp
+++ b/xbmc/listproviders/DirectoryProvider.cpp
@@ -36,6 +36,7 @@
#include "settings/Settings.h"
#include "threads/SingleLock.h"
#include "utils/JobManager.h"
+#include "utils/log.h"
#include "utils/SortUtils.h"
#include "utils/URIUtils.h"
#include "utils/Variant.h"
@@ -205,7 +206,13 @@ bool CDirectoryProvider::Update(bool forceRefresh)
fireJob |= UpdateSort();
fireJob |= UpdateLimit();
if (fireJob)
+ {
+ {
+ CSingleLock lock(m_section);
+ CLog::Log(LOGDEBUG, "CDirectoryProvider[%s]: refreshing..", m_currentUrl.c_str());
+ }
FireJob();
+ }
for (std::vector<CGUIStaticItemPtr>::iterator i = m_items.begin(); i != m_items.end(); ++i)
changed |= (*i)->UpdateVisibility(m_parentID);
@@ -253,6 +260,19 @@ void CDirectoryProvider::Fetch(std::vector<CGUIListItemPtr> &items) const
}
}
+void CDirectoryProvider::OnEvent(const ADDON::AddonEvent& event)
+{
+ CSingleLock lock(m_section);
+ if (URIUtils::IsProtocol(m_currentUrl, "addons"))
+ {
+ if (typeid(event) == typeid(ADDON::AddonEvents::Enabled) ||
+ typeid(event) == typeid(ADDON::AddonEvents::Disabled) ||
+ typeid(event) == typeid(ADDON::AddonEvents::InstalledChanged) ||
+ typeid(event) == typeid(ADDON::AddonEvents::MetadataChanged))
+ m_updateState = PENDING;
+ }
+}
+
void CDirectoryProvider::Reset(bool immediately /* = false */)
{
// cancel any pending jobs
@@ -271,7 +291,7 @@ void CDirectoryProvider::Reset(bool immediately /* = false */)
m_currentSort.sortOrder = SortOrderAscending;
m_currentLimit = 0;
m_updateState = OK;
- RegisterListProvider(false);
+ RegisterListProvider();
}
}
@@ -358,36 +378,41 @@ void CDirectoryProvider::FireJob()
m_jobID = CJobManager::GetInstance().AddJob(new CDirectoryJob(m_currentUrl, m_currentSort, m_currentLimit, m_parentID), this);
}
-void CDirectoryProvider::RegisterListProvider(bool hasLibraryContent)
+void CDirectoryProvider::RegisterListProvider()
{
- if (hasLibraryContent && !m_isAnnounced)
+ CSingleLock lock(m_section);
+ if (!m_isAnnounced)
{
m_isAnnounced = true;
CAnnouncementManager::GetInstance().AddAnnouncer(this);
+ ADDON::CAddonMgr::GetInstance().Events().Subscribe(this, &CDirectoryProvider::OnEvent);
}
- else if (!hasLibraryContent && m_isAnnounced)
+ else if (m_isAnnounced)
{
m_isAnnounced = false;
CAnnouncementManager::GetInstance().RemoveAnnouncer(this);
+ ADDON::CAddonMgr::GetInstance().Events().Unsubscribe(this);
}
}
bool CDirectoryProvider::UpdateURL()
{
- std::string value(m_url.GetLabel(m_parentID, false));
- if (value == m_currentUrl)
- return false;
-
- m_currentUrl = value;
+ {
+ CSingleLock lock(m_section);
+ std::string value(m_url.GetLabel(m_parentID, false));
+ if (value == m_currentUrl)
+ return false;
- // Register this provider only if we have library content
- RegisterListProvider(URIUtils::IsLibraryContent(m_currentUrl));
+ m_currentUrl = value;
+ }
+ RegisterListProvider();
return true;
}
bool CDirectoryProvider::UpdateLimit()
{
+ CSingleLock lock(m_section);
unsigned int value = m_limit.GetIntValue(m_parentID);
if (value == m_currentLimit)
return false;
@@ -399,6 +424,7 @@ bool CDirectoryProvider::UpdateLimit()
bool CDirectoryProvider::UpdateSort()
{
+ CSingleLock lock(m_section);
SortBy sortMethod(SortUtils::SortMethodFromString(m_sortMethod.GetLabel(m_parentID, false)));
SortOrder sortOrder(SortUtils::SortOrderFromString(m_sortOrder.GetLabel(m_parentID, false)));
if (sortOrder == SortOrderNone)
diff --git a/xbmc/listproviders/DirectoryProvider.h b/xbmc/listproviders/DirectoryProvider.h
index a15fdd2370..1b0a7e367c 100644
--- a/xbmc/listproviders/DirectoryProvider.h
+++ b/xbmc/listproviders/DirectoryProvider.h
@@ -22,7 +22,7 @@
#include <string>
#include <vector>
-
+#include "addons/AddonEvents.h"
#include "IListProvider.h"
#include "guilib/GUIStaticItem.h"
#include "utils/Job.h"
@@ -85,8 +85,9 @@ private:
CCriticalSection m_section;
void FireJob();
- void RegisterListProvider(bool hasLibraryContent);
+ void RegisterListProvider();
bool UpdateURL();
bool UpdateLimit();
bool UpdateSort();
+ void OnEvent(const ADDON::AddonEvent& event);
};
diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp
index d6138e04fe..e563222c21 100644
--- a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp
+++ b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp
@@ -37,14 +37,14 @@ CPeripheralBusAddon::CPeripheralBusAddon(CPeripherals *manager) :
CPeripheralBus("PeripBusAddon", manager, PERIPHERAL_BUS_ADDON)
{
CAddonMgr::GetInstance().RegisterAddonMgrCallback(ADDON_PERIPHERALDLL, this);
- CAddonMgr::GetInstance().RegisterObserver(this);
+ CAddonMgr::GetInstance().Events().Subscribe(this, &CPeripheralBusAddon::OnEvent);
UpdateAddons();
}
CPeripheralBusAddon::~CPeripheralBusAddon()
{
- CAddonMgr::GetInstance().UnregisterObserver(this);
+ CAddonMgr::GetInstance().Events().Unsubscribe(this);
CAddonMgr::GetInstance().UnregisterAddonMgrCallback(ADDON_PERIPHERALDLL);
// stop everything before destroying any (loaded) addons
@@ -293,9 +293,9 @@ bool CPeripheralBusAddon::RequestRemoval(ADDON::AddonPtr addon)
return true;
}
-void CPeripheralBusAddon::Notify(const Observable &obs, const ObservableMessage msg)
+void CPeripheralBusAddon::OnEvent(const ADDON::AddonEvent& event)
{
- if (msg == ObservableMessageAddons)
+ if (typeid(event) == typeid(AddonEvents::InstalledChanged))
UpdateAddons();
}
diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h
index 2f09b5acb3..626938db4c 100644
--- a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h
+++ b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h
@@ -34,8 +34,7 @@
namespace PERIPHERALS
{
class CPeripheralBusAddon : public CPeripheralBus,
- public ADDON::IAddonMgrCallback,
- public Observer
+ public ADDON::IAddonMgrCallback
{
public:
CPeripheralBusAddon(CPeripherals *manager);
@@ -76,9 +75,6 @@ namespace PERIPHERALS
bool RequestRestart(ADDON::AddonPtr addon, bool datachanged) override;
bool RequestRemoval(ADDON::AddonPtr addon) override;
- // implementation of Observer
- void Notify(const Observable &obs, const ObservableMessage msg) override;
-
bool SplitLocation(const std::string& strLocation, PeripheralAddonPtr& addon, unsigned int& peripheralIndex) const;
protected:
@@ -89,6 +85,7 @@ namespace PERIPHERALS
private:
void UpdateAddons(void);
+ void OnEvent(const ADDON::AddonEvent& event);
PeripheralAddonVector m_addons;
PeripheralAddonVector m_failedAddons;
diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt
index c495885fde..ea809a68fd 100644
--- a/xbmc/utils/CMakeLists.txt
+++ b/xbmc/utils/CMakeLists.txt
@@ -92,6 +92,8 @@ set(HEADERS ActorProtocol.h
DatabaseUtils.h
EndianSwap.h
Environment.h
+ EventStream.h
+ EventStreamDetail.h
Fanart.h
FileOperationJob.h
FileUtils.h
diff --git a/xbmc/utils/EventStream.h b/xbmc/utils/EventStream.h
new file mode 100644
index 0000000000..279a004942
--- /dev/null
+++ b/xbmc/utils/EventStream.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 Team Kodi
+ * http://kodi.tv
+ *
+ * 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, 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 XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "EventStreamDetail.h"
+#include "JobManager.h"
+#include "threads/CriticalSection.h"
+#include "threads/SingleLock.h"
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+
+template<typename Event>
+class CEventStream
+{
+public:
+
+ template<typename A>
+ void Subscribe(A* owner, void (A::*fn)(const Event&))
+ {
+ auto subscription = std::make_shared<detail::CSubscription<Event, A>>(owner, fn);
+ CSingleLock lock(m_criticalSection);
+ m_subscriptions.emplace_back(std::move(subscription));
+ }
+
+ template<typename A>
+ void Unsubscribe(A* obj)
+ {
+ std::vector<std::shared_ptr<detail::ISubscription<Event>>> toCancel;
+ {
+ CSingleLock lock(m_criticalSection);
+ auto it = m_subscriptions.begin();
+ while (it != m_subscriptions.end())
+ {
+ if ((*it)->IsOwnedBy(obj))
+ {
+ toCancel.push_back(*it);
+ it = m_subscriptions.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ }
+ for (auto& subscription : toCancel)
+ subscription->Cancel();
+ }
+
+protected:
+ std::vector<std::shared_ptr<detail::ISubscription<Event>>> m_subscriptions;
+ CCriticalSection m_criticalSection;
+};
+
+
+template<typename Event>
+class CEventSource : public CEventStream<Event>
+{
+public:
+ template<typename A>
+ void Publish(A event)
+ {
+ CSingleLock lock(this->m_criticalSection);
+ auto& subscriptions = this->m_subscriptions;
+ auto task = [subscriptions, event](){
+ for (auto& s: subscriptions)
+ s->HandleEvent(event);
+ };
+ lock.Leave();
+ CJobManager::GetInstance().Submit(std::move(task));
+ }
+};
diff --git a/xbmc/utils/EventStreamDetail.h b/xbmc/utils/EventStreamDetail.h
new file mode 100644
index 0000000000..68d97c2e07
--- /dev/null
+++ b/xbmc/utils/EventStreamDetail.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 Team Kodi
+ * http://kodi.tv
+ *
+ * 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, 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 XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "threads/CriticalSection.h"
+#include "threads/SingleLock.h"
+
+namespace detail
+{
+
+template<typename Event>
+class ISubscription
+{
+public:
+ virtual void HandleEvent(const Event& event) = 0;
+ virtual void Cancel() = 0;
+ virtual bool IsOwnedBy(void* obj) = 0;
+ virtual ~ISubscription() {}
+};
+
+template<typename Event, typename Owner>
+class CSubscription : public ISubscription<Event>
+{
+public:
+ typedef void (Owner::*Fn)(const Event&);
+ CSubscription(Owner* owner, Fn fn);
+ void HandleEvent(const Event& event) override;
+ void Cancel() override;
+ bool IsOwnedBy(void *obj) override;
+
+private:
+ Owner* m_owner;
+ Fn m_eventHandler;
+ CCriticalSection m_criticalSection;
+};
+
+template<typename Event, typename Owner>
+CSubscription<Event, Owner>::CSubscription(Owner* owner, Fn fn)
+ : m_owner(owner), m_eventHandler(fn)
+{}
+
+template<typename Event, typename Owner>
+bool CSubscription<Event, Owner>::IsOwnedBy(void* obj)
+{
+ CSingleLock lock(m_criticalSection);
+ return obj != nullptr && obj == m_owner;
+}
+
+template<typename Event, typename Owner>
+void CSubscription<Event, Owner>::Cancel()
+{
+ CSingleLock lock(m_criticalSection);
+ m_owner = nullptr;
+}
+
+template<typename Event, typename Owner>
+void CSubscription<Event, Owner>::HandleEvent(const Event& event)
+{
+ CSingleLock lock(m_criticalSection);
+ if (m_owner)
+ (m_owner->*m_eventHandler)(event);
+}
+}
diff --git a/xbmc/windows/GUIMediaWindow.cpp b/xbmc/windows/GUIMediaWindow.cpp
index 075d5317f5..ad9c6bbb2f 100644
--- a/xbmc/windows/GUIMediaWindow.cpp
+++ b/xbmc/windows/GUIMediaWindow.cpp
@@ -653,16 +653,7 @@ bool CGUIMediaWindow::GetDirectory(const std::string &strDirectory, CFileItemLis
CLog::Log(LOGDEBUG," ParentPath = [%s]", CURL::GetRedacted(strParentPath).c_str());
if (pathToUrl.IsProtocol("plugin"))
- {
- //Record usage
- auto& addonId = pathToUrl.GetHostName();
- auto time = CDateTime::GetCurrentDateTime();
- CJobManager::GetInstance().Submit([addonId, time](){
- CAddonDatabase db;
- if (db.Open())
- db.SetLastUsed(addonId, time);
- });
- }
+ CAddonMgr::GetInstance().UpdateLastUsed(pathToUrl.GetHostName());
// see if we can load a previously cached folder
CFileItemList cachedItems(strDirectory);
@@ -930,15 +921,8 @@ bool CGUIMediaWindow::OnClick(int iItem, const std::string &player)
{
if (!CScriptInvocationManager::GetInstance().Stop(addon->LibPath()))
{
- auto time = CDateTime::GetCurrentDateTime();
-
+ CAddonMgr::GetInstance().UpdateLastUsed(addon->ID());
CScriptInvocationManager::GetInstance().ExecuteAsync(addon->LibPath(), addon);
-
- CJobManager::GetInstance().Submit([addon, time](){
- CAddonDatabase db;
- if (db.Open())
- db.SetLastUsed(addon->ID(), time);
- });
}
return true;
}