diff options
57 files changed, 731 insertions, 317 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj index ae7bd4db5c..c6cdb0e8a9 100644 --- a/Kodi.xcodeproj/project.pbxproj +++ b/Kodi.xcodeproj/project.pbxproj @@ -393,6 +393,8 @@ 7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C5608C40F1754930056433A /* ExternalPlayer.cpp */; }; 7C62F24210505BC7002AD2C1 /* Bookmark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C62F24010505BC7002AD2C1 /* Bookmark.cpp */; }; 7C62F45E1057A62D002AD2C1 /* DirectoryNodeSingles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C62F45C1057A62D002AD2C1 /* DirectoryNodeSingles.cpp */; }; + 7C68401B1D87C6D400C55360 /* ViewModeSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6840191D87C6D400C55360 /* ViewModeSettings.cpp */; }; + 7C68401C1D87C6D400C55360 /* ViewModeSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6840191D87C6D400C55360 /* ViewModeSettings.cpp */; }; 7C6EB330155BD1D40080368A /* ImageFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB32E155BD1D40080368A /* ImageFile.cpp */; }; 7C6EB6FA155F32C30080368A /* HTTPImageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */; }; 7C779E3A104A57E500F444C4 /* RenderSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C779E1F104A57E500F444C4 /* RenderSystem.cpp */; }; @@ -2941,6 +2943,8 @@ 7C62F24110505BC7002AD2C1 /* Bookmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bookmark.h; sourceTree = "<group>"; }; 7C62F45C1057A62D002AD2C1 /* DirectoryNodeSingles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectoryNodeSingles.cpp; sourceTree = "<group>"; }; 7C62F45D1057A62D002AD2C1 /* DirectoryNodeSingles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryNodeSingles.h; sourceTree = "<group>"; }; + 7C6840191D87C6D400C55360 /* ViewModeSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ViewModeSettings.cpp; sourceTree = "<group>"; }; + 7C68401A1D87C6D400C55360 /* ViewModeSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewModeSettings.h; sourceTree = "<group>"; }; 7C6EB32E155BD1D40080368A /* ImageFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFile.cpp; sourceTree = "<group>"; }; 7C6EB32F155BD1D40080368A /* ImageFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFile.h; sourceTree = "<group>"; }; 7C6EB6F8155F32C30080368A /* HTTPImageHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPImageHandler.cpp; sourceTree = "<group>"; }; @@ -6031,6 +6035,8 @@ F59876BE0FBA351D008EF4FB /* VideoReferenceClock.h */, 7CC30DBE16291C2C003E7579 /* VideoThumbLoader.cpp */, 7CC30DBF16291C2C003E7579 /* VideoThumbLoader.h */, + 7C6840191D87C6D400C55360 /* ViewModeSettings.cpp */, + 7C68401A1D87C6D400C55360 /* ViewModeSettings.h */, ); path = video; sourceTree = "<group>"; @@ -10113,6 +10119,7 @@ E38A06CE0D95AA5500FF8227 /* GUIDialogKaiToast.cpp in Sources */, 7C8E023D1BA35D0B0072E8B2 /* ProfileBuiltins.cpp in Sources */, E3B53E7C0D97B08100021A96 /* DVDSubtitleParserMicroDVD.cpp in Sources */, + 7C68401B1D87C6D400C55360 /* ViewModeSettings.cpp in Sources */, E36C29DF0DA72429001F0C9D /* Artist.cpp in Sources */, E36C29E00DA72429001F0C9D /* Album.cpp in Sources */, E36C29E60DA72442001F0C9D /* DVDSubtitleParserSami.cpp in Sources */, @@ -11451,6 +11458,7 @@ E49913AE174E5F3300741B6D /* UPnPPlayer.cpp in Sources */, E49913AF174E5F3300741B6D /* UPnPRenderer.cpp in Sources */, E49913B0174E5F3300741B6D /* UPnPServer.cpp in Sources */, + 7C68401C1D87C6D400C55360 /* ViewModeSettings.cpp in Sources */, E49913B1174E5F3300741B6D /* UPnPSettings.cpp in Sources */, E49913B2174E5F3700741B6D /* WebSocket.cpp in Sources */, E49913B3174E5F3700741B6D /* WebSocketManager.cpp in Sources */, diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 3de62d4e54..7a3854a464 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -10354,7 +10354,13 @@ msgctxt "#19295" msgid "Delete timer rule" msgstr "" -#empty strings from id 19296 to 19498 +#. Label if no pvr addons are enabled +#: xbmc/pvr/windows/GUIWindowPVRBase.cpp +msgctxt "#19296" +msgid "No PVR add-on enabled" +msgstr "" + +#empty strings from id 19297 to 19498 #: xbmc/epg/Epg.cpp msgctxt "#19499" @@ -13448,10 +13454,14 @@ msgctxt "#21844" msgid "XP comment" msgstr "" +#. Used in context menu +#: xbmc/video/windows/GUIWindowVideoNav.cpp msgctxt "#21845" msgid "Scan to library" msgstr "" +#empty strings from id 21846 to 21856 + msgctxt "#21857" msgid "Sub-location" msgstr "" @@ -14089,11 +14099,7 @@ msgctxt "#24043" msgid "Available updates" msgstr "" -#: xbmc/addons/AddonInstaller.cpp -#: xbmc/addons/AddonsDatabase.cpp -msgctxt "#24044" -msgid "Dependencies not met. Please contact add-on author." -msgstr "" +# empty string 24043 #. Used as an event log description for add-ons failed to install from zip #: xbmc/addons/AddonInstaller.cpp @@ -14116,10 +14122,7 @@ msgctxt "#24048" msgid "VideoPlayer InputStream" msgstr "" -#: xbmc/filesystem/AddonsDirectory.cpp -msgctxt "#24049" -msgid "Incompatible" -msgstr "" +# empty string 24049 #: unknown msgctxt "#24050" @@ -14638,7 +14641,15 @@ msgctxt "#24147" msgid "Failed to scan %s: %s" msgstr "" -#empty strings from id 24148 to 24990 +msgctxt "#24148" +msgid "Incompatible add-ons" +msgstr "" + +msgctxt "#24149" +msgid "The following add-ons are incompatible with this version of Kodi and have been automatically disabled: %s." +msgstr "" + +#empty strings from id 24150 to 24990 #. Used as error message in add-on browser when add-on repository data could not be downloaded #: xbmc/filesystem/AddonsDirectory.cpp @@ -15248,18 +15259,6 @@ msgctxt "#29985" msgid "If traffic advisory is send from RDS, volume is increased" msgstr "" -#. Boolean value on settings -#: system/settings/settings.xml -msgctxt "#29986" -msgid "Publicate traffic messages" -msgstr "" - -#. Help text of boolean on/off value -#: system/settings/settings.xml -msgctxt "#29987" -msgid "Send present traffic messages around and can be handled from add-ons (nothing inside Kodi)" -msgstr "" - #. Music role category #: system/library/music/musicroles/Arrangers.xml msgctxt "#29988" @@ -19584,3 +19583,13 @@ msgstr "" msgctxt "#39007" msgid "This provides access to where picture sources can be added and otherwise managed." msgstr "" + +#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp +msgctxt "#39008" +msgid "Zoom - 120% width" +msgstr "" + +#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp +msgctxt "#39009" +msgid "Zoom - 110% width" +msgstr "" diff --git a/addons/skin.estuary/1080i/MyPVRGuide.xml b/addons/skin.estuary/1080i/MyPVRGuide.xml index 6f9f118aae..6a1cd6a225 100644 --- a/addons/skin.estuary/1080i/MyPVRGuide.xml +++ b/addons/skin.estuary/1080i/MyPVRGuide.xml @@ -27,11 +27,12 @@ <top>0</top> <width>1700</width> <height>510</height> - <pagecontrol>10</pagecontrol> + <pagecontrol>60</pagecontrol> <scrolltime tween="quadratic" easing="out">200</scrolltime> <timeblocks>36</timeblocks> <rulerunit>6</rulerunit> <onleft>9000</onleft> + <onright>60</onright> <onup>10</onup> <ondown>10</ondown> <viewtype label="19032">list</viewtype> @@ -154,6 +155,16 @@ </control> </focusedlayout> </control> + <control type="scrollbar" id="60"> + <right>85</right> + <top>45</top> + <width>13</width> + <height>465</height> + <onleft>10</onleft> + <onright>10</onright> + <orientation>vertical</orientation> + <texturesliderbackground colordiffuse="22FFFFFF">colors/white.png</texturesliderbackground> + </control> <control type="group"> <top>540</top> <left>-120</left> diff --git a/project/cmake/cpack/deb/packages/kodi-peripheral-dev.txt.in b/project/cmake/cpack/deb/packages/kodi-peripheral-dev.txt.in new file mode 100644 index 0000000000..1c41c5f5d2 --- /dev/null +++ b/project/cmake/cpack/deb/packages/kodi-peripheral-dev.txt.in @@ -0,0 +1,24 @@ +# kodi-peripheral-dev debian package metadata +# +# Setting PACKAGE_SHLIBDEPS to 'ON' will cause CPack to ignore PACKAGE_DEPENDS +# content and use dpkg-shlibdeps to automatically generate the package dependency +# list. Only useful for packages that contain binaries. +# +# PACKAGE_ARCHITECTURE should be set to 'all' only if package contains +# architecture agnostic data. CPack will set proper architecture (amd64/i386/etc) +# based on build options. +# +# Remaining settings are (hopefully) self-explanatory. + +PACKAGE_NAME @APP_NAME_LC@-peripheral-dev +PACKAGE_ARCHITECTURE all +PACKAGE_SECTION libdevel +PACKAGE_PRIORITY optional +PACKAGE_SHLIBDEPS +PACKAGE_DEPENDS @APP_NAME_LC@-addon-dev +PACKAGE_RECOMMENDS +PACKAGE_SUGGESTS +PACKAGE_BREAKS +PACKAGE_REPLACES +PACKAGE_DESCRIPTION_HEADER @APP_NAME@ Media Center (peripheral add-ons dev package) +PACKAGE_DESCRIPTION_FOOTER This is the development package for @APP_NAME@'s peripheral add-ons. diff --git a/project/cmake/scripts/linux/Install.cmake b/project/cmake/scripts/linux/Install.cmake index ba90de4a35..fac75eddf2 100644 --- a/project/cmake/scripts/linux/Install.cmake +++ b/project/cmake/scripts/linux/Install.cmake @@ -139,6 +139,7 @@ install(PROGRAMS ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/texturepacker/TexturePack # Install kodi-addon-dev headers install(FILES ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_types.h + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_vfs_utils.hpp ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_adsp.h ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_audioengine.h ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/libKODI_guilib.h @@ -297,6 +298,14 @@ install(FILES ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbm DESTINATION ${includedir}/${APP_NAME_LC} COMPONENT kodi-visualization-dev) +# Install kodi-peripheral-dev +install(FILES ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_callbacks.h + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h + ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp + DESTINATION ${includedir}/${APP_NAME_LC} + COMPONENT kodi-peripheral-dev) + # Install XBT skin files foreach(texture ${XBT_FILES}) string(REPLACE "${CMAKE_BINARY_DIR}/" "" dir ${texture}) diff --git a/system/settings/settings.xml b/system/settings/settings.xml index ca912cd996..8d20a7ae8f 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -1477,11 +1477,6 @@ <dependency type="enable" setting="pvrplayback.trafficadvisory">true</dependency> </dependencies> </setting> - <setting id="pvrplayback.sendrdstrafficmsg" type="boolean" label="29986" help="29987"> - <level>2</level> - <default>false</default> - <control type="toggle" /> - </setting> </group> </category> <category id="pvrrecord" label="19043" help="36233"> diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 775063a7a9..45cc633fcd 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -280,7 +280,7 @@ CApplication::CApplication(void) m_nextPlaylistItem = -1; m_bPlaybackStarting = false; m_ePlayState = PLAY_STATE_NONE; - m_skinReverting = false; + m_confirmSkinChange = true; #ifdef HAS_GLX XInitThreads(); @@ -1164,12 +1164,19 @@ bool CApplication::Initialize() if (g_advancedSettings.m_splashImage) g_windowManager.ActivateWindow(WINDOW_SPLASH); - // Make sure we have at least the default skin + m_confirmSkinChange = false; + m_incompatibleAddons = CAddonSystemSettings::GetInstance().MigrateAddons(); + m_confirmSkinChange = true; + std::string defaultSkin = ((const CSettingString*)CSettings::GetInstance().GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN))->GetDefault(); - if (!LoadSkin(CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKIN)) && !LoadSkin(defaultSkin)) + if (!LoadSkin(CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKIN))) { - CLog::Log(LOGERROR, "Default skin '%s' not found! Terminating..", defaultSkin.c_str()); - return false; + CLog::Log(LOGERROR, "Failed to load skin '%s'", CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKIN).c_str()); + if (!LoadSkin(defaultSkin)) + { + CLog::Log(LOGFATAL, "Default skin '%s' could not be loaded! Terminating..", defaultSkin.c_str()); + return false; + } } if (CSettings::GetInstance().GetBool(CSettings::SETTING_MASTERLOCK_STARTUPLOCK) && @@ -1249,8 +1256,6 @@ bool CApplication::Initialize() CLog::Log(LOGNOTICE, "initialize done"); - m_bInitializing = false; - // reset our screensaver (starts timers etc.) ResetScreenSaver(); @@ -1406,11 +1411,14 @@ void CApplication::OnSettingChanged(const CSetting *setting) // reset the settings to ignore during changing skins m_skinReloadSettingIgnore.clear(); - // now we can finally reload skins - std::string builtin("ReloadSkin"); - if (settingId == CSettings::SETTING_LOOKANDFEEL_SKIN && !m_skinReverting) - builtin += "(confirm)"; - CApplicationMessenger::GetInstance().PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, builtin); + if (g_SkinInfo) + { + // now we can finally reload skins + std::string builtin("ReloadSkin"); + if (settingId == CSettings::SETTING_LOOKANDFEEL_SKIN && m_confirmSkinChange) + builtin += "(confirm)"; + CApplicationMessenger::GetInstance().PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, builtin); + } } else if (settingId == CSettings::SETTING_LOOKANDFEEL_SKINZOOM) { @@ -1549,7 +1557,10 @@ bool CApplication::OnSettingsSaving() const void CApplication::ReloadSkin(bool confirm/*=false*/) { - std::string oldSkin = g_SkinInfo ? g_SkinInfo->ID() : ""; + if (!g_SkinInfo || m_bInitializing) + return; // Don't allow reload before skin is loaded by system + + std::string oldSkin = g_SkinInfo->ID(); CGUIMessage msg(GUI_MSG_LOAD_SKIN, -1, g_windowManager.GetActiveWindow()); g_windowManager.SendMessage(msg); @@ -1557,18 +1568,15 @@ void CApplication::ReloadSkin(bool confirm/*=false*/) std::string newSkin = CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKIN); if (LoadSkin(newSkin)) { - /* The Reset() or SetString() below will cause recursion, so the m_skinReverting boolean is set so as to not prompt the + /* The Reset() or SetString() below will cause recursion, so the m_confirmSkinChange boolean is set so as to not prompt the user as to whether they want to keep the current skin. */ - if (confirm && !m_skinReverting) + if (confirm && m_confirmSkinChange) { if (HELPERS::ShowYesNoDialogText(CVariant{13123}, CVariant{13111}, CVariant{""}, CVariant{""}, 10000) != DialogResponse::YES) { - m_skinReverting = true; - if (oldSkin.empty()) - CSettings::GetInstance().GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN)->Reset(); - else - CSettings::GetInstance().SetString(CSettings::SETTING_LOOKANDFEEL_SKIN, oldSkin); + m_confirmSkinChange = false; + CSettings::GetInstance().SetString(CSettings::SETTING_LOOKANDFEEL_SKIN, oldSkin); } } } @@ -1578,12 +1586,12 @@ void CApplication::ReloadSkin(bool confirm/*=false*/) std::string defaultSkin = ((CSettingString*)CSettings::GetInstance().GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN))->GetDefault(); if (newSkin != defaultSkin) { - m_skinReverting = true; + m_confirmSkinChange = false; CSettings::GetInstance().GetSetting(CSettings::SETTING_LOOKANDFEEL_SKIN)->Reset(); CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(24102), g_localizeStrings.Get(24103)); } } - m_skinReverting = false; + m_confirmSkinChange = true; } bool CApplication::Load(const TiXmlNode *settings) @@ -1620,20 +1628,13 @@ bool CApplication::Save(TiXmlNode *settings) const bool CApplication::LoadSkin(const std::string& skinID) { - AddonPtr addon; - if (CAddonMgr::GetInstance().GetAddon(skinID, addon, ADDON_SKIN)) + SkinPtr skin; { - if (LoadSkin(std::dynamic_pointer_cast<ADDON::CSkinInfo>(addon))) - return true; + AddonPtr addon; + if (!CAddonMgr::GetInstance().GetAddon(skinID, addon, ADDON_SKIN)) + return false; + skin = std::static_pointer_cast<ADDON::CSkinInfo>(addon); } - CLog::Log(LOGERROR, "failed to load requested skin '%s'", skinID.c_str()); - return false; -} - -bool CApplication::LoadSkin(const SkinPtr& skin) -{ - if (!skin) - return false; // start/prepare the skin skin->Start(); @@ -1643,7 +1644,10 @@ bool CApplication::LoadSkin(const SkinPtr& skin) // check if the skin has been properly loaded and if it has a Home.xml if (!skin->HasSkinFile("Home.xml")) + { + CLog::Log(LOGERROR, "failed to load requested skin '%s'", skin->ID().c_str()); return false; + } bool bPreviousPlayingState=false; bool bPreviousRenderingState=false; @@ -1675,7 +1679,6 @@ bool CApplication::LoadSkin(const SkinPtr& skin) CLog::Log(LOGINFO, " load skin from: %s (version: %s)", skin->Path().c_str(), skin->Version().asString().c_str()); g_SkinInfo = skin; - g_SkinInfo->Start(); CLog::Log(LOGINFO, " load fonts for skin..."); g_graphicsContext.SetMediaDir(skin->Path()); @@ -4159,8 +4162,18 @@ bool CApplication::OnMessage(CGUIMessage& message) if (m_fallbackLanguageLoaded) CGUIDialogOK::ShowAndGetInput(CVariant{24133}, CVariant{24134}); + if (!m_incompatibleAddons.empty()) + { + auto addonList = StringUtils::Join(m_incompatibleAddons, ", "); + auto msg = StringUtils::Format(g_localizeStrings.Get(24149).c_str(), addonList.c_str()); + CGUIDialogOK::ShowAndGetInput(CVariant{24148}, CVariant{std::move(msg)}); + m_incompatibleAddons.clear(); + } + // show info dialog about moved configuration files if needed ShowAppMigrationMessage(); + + m_bInitializing = false; } } break; diff --git a/xbmc/Application.h b/xbmc/Application.h index c14f62d54f..d20b7725e2 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h @@ -23,6 +23,7 @@ #include "system.h" // for HAS_DVD_DRIVE et. al. #include "XBApplicationEx.h" +#include "addons/AddonSystemSettings.h" #include "guilib/IMsgTargetCallback.h" #include "guilib/Resolution.h" #include "utils/GlobalsHandling.h" @@ -145,7 +146,7 @@ public: virtual void FrameMove(bool processEvents, bool processGUI = true) override; virtual void Render() override; virtual void Preflight(); - virtual bool Create() override; + bool Create(); virtual bool Cleanup() override; bool CreateGUI(); @@ -416,8 +417,7 @@ protected: virtual bool OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode) override; bool LoadSkin(const std::string& skinID); - bool LoadSkin(const std::shared_ptr<ADDON::CSkinInfo>& skin); - + /*! \brief Delegates the action to all registered action handlers. \param action The action @@ -425,7 +425,7 @@ protected: */ bool NotifyActionListeners(const CAction &action) const; - bool m_skinReverting; + bool m_confirmSkinChange; std::string m_skinReloadSettingIgnore; bool m_saveSkinOnUnloading; @@ -522,7 +522,9 @@ protected: std::vector<IActionListener *> m_actionListeners; bool m_fallbackLanguageLoaded; - + + std::vector<std::string> m_incompatibleAddons; /*!< Result of addon migration */ + private: CCriticalSection m_critSection; /*!< critical section for all changes to this class, except for changes to triggers */ diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp index 6648fb8d64..0115337916 100644 --- a/xbmc/GUIInfoManager.cpp +++ b/xbmc/GUIInfoManager.cpp @@ -10561,11 +10561,7 @@ std::string CGUIInfoManager::GetItemLabel(const CFileItem *item, int info, std:: break; case LISTITEM_ADDON_BROKEN: if (item->HasAddonInfo()) - { - if (item->GetAddonInfo()->Broken() == "DEPSNOTMET") - return g_localizeStrings.Get(24044); return item->GetAddonInfo()->Broken(); - } break; case LISTITEM_ADDON_TYPE: if (item->HasAddonInfo()) diff --git a/xbmc/NfoFile.cpp b/xbmc/NfoFile.cpp index 02228e108e..2f871e778e 100644 --- a/xbmc/NfoFile.cpp +++ b/xbmc/NfoFile.cpp @@ -24,6 +24,7 @@ #include "NfoFile.h" #include "video/VideoInfoDownloader.h" #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "filesystem/File.h" #include "FileItem.h" #include "music/Album.h" @@ -46,7 +47,7 @@ CNfoFile::NFOResult CNfoFile::Create(const std::string& strPath, const ScraperPt AddonPtr addon; ScraperPtr defaultScraper; - if (CAddonMgr::GetInstance().GetDefault(m_type, addon)) + if (CAddonSystemSettings::GetInstance().GetActive(m_type, addon)) defaultScraper = std::dynamic_pointer_cast<CScraper>(addon); if (m_type == ADDON_SCRAPER_ALBUMS) diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp index 618e7dc98b..9fb278691e 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp @@ -145,9 +145,12 @@ std::string GetHomePath(const std::string& strTarget, std::string strPath) { strPathW = buf.get(); CWIN32Util::RemoveExtraLongPathPrefix(strPathW); - g_charsetConverter.wToUTF8(strPathW, strPath); + if (IsDirectoryValidRoot(strPathW)) + { + g_charsetConverter.wToUTF8(strPathW, strPath); return strPath; + } } } } @@ -172,16 +175,18 @@ std::string GetHomePath(const std::string& strTarget, std::string strPath) auto bufSize = GetCurrentDirectoryW(0, nullptr); if (bufSize > 0) { - auto buf = new wchar_t[bufSize]; - if (0 != GetCurrentDirectoryW(bufSize, buf)) + auto buf = std::make_unique<wchar_t[]>(bufSize); + if (0 != GetCurrentDirectoryW(bufSize, buf.get())) { std::string currentDirectory; - std::wstring currentDirectoryW(buf); + std::wstring currentDirectoryW(buf.get()); CWIN32Util::RemoveExtraLongPathPrefix(currentDirectoryW); - g_charsetConverter.wToUTF8(currentDirectoryW, currentDirectory); - + if (IsDirectoryValidRoot(currentDirectoryW)) + { + g_charsetConverter.wToUTF8(currentDirectoryW, currentDirectory); return currentDirectory; + } } } diff --git a/xbmc/XBApplicationEx.cpp b/xbmc/XBApplicationEx.cpp index f6fffd8f6e..473a973df0 100644 --- a/xbmc/XBApplicationEx.cpp +++ b/xbmc/XBApplicationEx.cpp @@ -50,24 +50,6 @@ CXBApplicationEx::~CXBApplicationEx() { } -/* Create the app */ -bool CXBApplicationEx::Create() -{ - // Variables to perform app timing - m_bStop = false; - m_AppFocused = true; - m_ExitCode = EXITCODE_QUIT; - - // Initialize the app's device-dependent objects - if (!Initialize()) - { - CLog::Log(LOGERROR, "XBAppEx: Call to Initialize() failed!" ); - return false; - } - - return true; -} - /* Destroy the app */ VOID CXBApplicationEx::Destroy() { diff --git a/xbmc/XBApplicationEx.h b/xbmc/XBApplicationEx.h index c46cba15b1..f8b8c6deb0 100644 --- a/xbmc/XBApplicationEx.h +++ b/xbmc/XBApplicationEx.h @@ -49,8 +49,6 @@ public: virtual void SetRenderGUI(bool renderGUI) {}; public: - // Functions to create, run, and clean up the application - virtual bool Create(); INT Run(); VOID Destroy(); diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp index a2551d6ff5..476ab29741 100644 --- a/xbmc/addons/Addon.cpp +++ b/xbmc/addons/Addon.cpp @@ -348,8 +348,11 @@ void OnEnabled(const std::string& id) CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_ADSPDLL)) return addon->OnEnabled(); - if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_SERVICE)) - std::static_pointer_cast<CService>(addon)->Start(); + if (CAddonMgr::GetInstance().ServicesHasStarted()) + { + if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_SERVICE)) + std::static_pointer_cast<CService>(addon)->Start(); + } if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_REPOSITORY)) CRepositoryUpdater::GetInstance().ScheduleUpdate(); //notify updater there is a new addon @@ -357,13 +360,17 @@ void OnEnabled(const std::string& id) void OnDisabled(const std::string& id) { + AddonPtr addon; if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_PVRDLL, false) || CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_ADSPDLL, false)) return addon->OnDisabled(); - if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_SERVICE, false)) - std::static_pointer_cast<CService>(addon)->Stop(); + if (CAddonMgr::GetInstance().ServicesHasStarted()) + { + if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_SERVICE, false)) + std::static_pointer_cast<CService>(addon)->Stop(); + } if (CAddonMgr::GetInstance().GetAddon(id, addon, ADDON_CONTEXT_ITEM, false)) CContextMenuManager::GetInstance().Unload(*std::static_pointer_cast<CContextMenuAddon>(addon)); @@ -374,8 +381,12 @@ void OnPreInstall(const AddonPtr& addon) //Before installing we need to stop/unregister any local addon //that have this id, regardless of what the 'new' addon is. AddonPtr localAddon; - if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) - std::static_pointer_cast<CService>(localAddon)->Stop(); + + if (CAddonMgr::GetInstance().ServicesHasStarted()) + { + if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) + std::static_pointer_cast<CService>(localAddon)->Stop(); + } if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_CONTEXT_ITEM)) CContextMenuManager::GetInstance().Unload(*std::static_pointer_cast<CContextMenuAddon>(localAddon)); @@ -388,8 +399,11 @@ void OnPreInstall(const AddonPtr& addon) void OnPostInstall(const AddonPtr& addon, bool update, bool modal) { AddonPtr localAddon; - if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) - std::static_pointer_cast<CService>(localAddon)->Start(); + if (CAddonMgr::GetInstance().ServicesHasStarted()) + { + if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) + std::static_pointer_cast<CService>(localAddon)->Start(); + } if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_REPOSITORY)) CRepositoryUpdater::GetInstance().ScheduleUpdate(); //notify updater there is a new addon or version @@ -400,8 +414,12 @@ void OnPostInstall(const AddonPtr& addon, bool update, bool modal) void OnPreUnInstall(const AddonPtr& addon) { AddonPtr localAddon; - if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) - std::static_pointer_cast<CService>(localAddon)->Stop(); + + if (CAddonMgr::GetInstance().ServicesHasStarted()) + { + if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_SERVICE)) + std::static_pointer_cast<CService>(localAddon)->Stop(); + } if (CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon, ADDON_CONTEXT_ITEM)) CContextMenuManager::GetInstance().Unload(*std::static_pointer_cast<CContextMenuAddon>(localAddon)); diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp index 5fb65055a0..d252b94084 100644 --- a/xbmc/addons/AddonInstaller.cpp +++ b/xbmc/addons/AddonInstaller.cpp @@ -63,7 +63,7 @@ struct find_map : public std::binary_function<CAddonInstaller::JobMap::value_typ } }; -CAddonInstaller::CAddonInstaller() +CAddonInstaller::CAddonInstaller() : m_idle(true) { } CAddonInstaller::~CAddonInstaller() @@ -81,6 +81,8 @@ void CAddonInstaller::OnJobComplete(unsigned int jobID, bool success, CJob* job) JobMap::iterator i = find_if(m_downloadJobs.begin(), m_downloadJobs.end(), bind2nd(find_map(), jobID)); if (i != m_downloadJobs.end()) m_downloadJobs.erase(i); + if (m_downloadJobs.empty()) + m_idle.Set(); lock.Leave(); PrunePackageCache(); @@ -150,6 +152,8 @@ bool CAddonInstaller::Cancel(const std::string &addonID) { CJobManager::GetInstance().CancelJob(i->second.jobID); m_downloadJobs.erase(i); + if (m_downloadJobs.empty()) + m_idle.Set(); return true; } @@ -188,6 +192,7 @@ bool CAddonInstaller::InstallModal(const std::string &addonID, ADDON::AddonPtr & return CAddonMgr::GetInstance().GetAddon(addonID, addon); } + bool CAddonInstaller::InstallOrUpdate(const std::string &addonID, bool background /* = true */, bool modal /* = false */) { AddonPtr addon; @@ -239,10 +244,12 @@ bool CAddonInstaller::DoInstall(const AddonPtr &addon, const RepositoryPtr& repo { unsigned int jobID = CJobManager::GetInstance().AddJob(installJob, this); m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(jobID))); + m_idle.Reset(); return true; } m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(0))); + m_idle.Reset(); lock.Leave(); bool result = false; @@ -255,6 +262,8 @@ bool CAddonInstaller::DoInstall(const AddonPtr &addon, const RepositoryPtr& repo lock.Enter(); JobMap::iterator i = m_downloadJobs.find(addon->ID()); m_downloadJobs.erase(i); + if (m_downloadJobs.empty()) + m_idle.Set(); return result; } @@ -345,10 +354,10 @@ bool CAddonInstaller::CheckDependencies(const AddonPtr &addon, //! @todo should we assume that installed deps are OK? if (dep && std::find(preDeps.begin(), preDeps.end(), dep->ID()) == preDeps.end()) { + preDeps.push_back(dep->ID()); if (!CheckDependencies(dep, preDeps, database, failedDep)) { database.Close(); - preDeps.push_back(dep->ID()); return false; } } @@ -418,13 +427,22 @@ void CAddonInstaller::PrunePackageCache() delete it->second; } -void CAddonInstaller::InstallUpdates(bool includeBlacklisted /* = false */) +void CAddonInstaller::InstallUpdates() { - for (const auto& addon : CAddonMgr::GetInstance().GetAvailableUpdates()) + auto updates = CAddonMgr::GetInstance().GetAvailableUpdates(); + for (const auto& addon : updates) { - if (includeBlacklisted || !CAddonMgr::GetInstance().IsBlacklisted(addon->ID())) + if (!CAddonMgr::GetInstance().IsBlacklisted(addon->ID())) CAddonInstaller::GetInstance().InstallOrUpdate(addon->ID()); } + + CSingleLock lock(m_critSection); + if (!m_downloadJobs.empty()) + { + m_idle.Reset(); + lock.Leave(); + m_idle.Wait(); + } } bool CAddonInstaller::GetRepoForAddon(const std::string& addonId, RepositoryPtr& repoPtr) diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h index 02c71855d4..61d13ffea1 100644 --- a/xbmc/addons/AddonInstaller.h +++ b/xbmc/addons/AddonInstaller.h @@ -94,7 +94,8 @@ public: */ bool HasJob(const std::string& ID) const; - void InstallUpdates(bool includeBlacklisted = false); + /*! Install update and block until all updates have installed. */ + void InstallUpdates(); void OnJobComplete(unsigned int jobID, bool success, CJob* job); void OnJobProgress(unsigned int jobID, unsigned int progress, unsigned int total, const CJob *job); @@ -152,6 +153,7 @@ private: CCriticalSection m_critSection; JobMap m_downloadJobs; + CEvent m_idle; }; class CAddonInstallJob : public CFileOperationJob diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 9a4225c050..8dec0bbd38 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -257,7 +257,8 @@ static bool LoadManifest(std::set<std::string>& system, std::set<std::string>& o CAddonMgr::CAddonMgr() : m_cp_context(nullptr), - m_cpluff(nullptr) + m_cpluff(nullptr), + m_serviceSystemStarted(false) { } CAddonMgr::~CAddonMgr() @@ -610,89 +611,6 @@ bool CAddonMgr::GetAddon(const std::string &str, AddonPtr &addon, const TYPE &ty return false; } -//! @todo handle all 'default' cases here, not just scrapers & vizs -bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon) -{ - std::string setting; - switch (type) - { - case ADDON_VIZ: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_MUSICPLAYER_VISUALISATION); - break; - case ADDON_SCREENSAVER: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_SCREENSAVER_MODE); - break; - case ADDON_SCRAPER_ALBUMS: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_MUSICLIBRARY_ALBUMSSCRAPER); - break; - case ADDON_SCRAPER_ARTISTS: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_MUSICLIBRARY_ARTISTSSCRAPER); - break; - case ADDON_SCRAPER_MOVIES: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_SCRAPERS_MOVIESDEFAULT); - break; - case ADDON_SCRAPER_MUSICVIDEOS: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_SCRAPERS_MUSICVIDEOSDEFAULT); - break; - case ADDON_SCRAPER_TVSHOWS: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_SCRAPERS_TVSHOWSDEFAULT); - break; - case ADDON_WEB_INTERFACE: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_SERVICES_WEBSKIN); - break; - case ADDON_RESOURCE_LANGUAGE: - setting = CSettings::GetInstance().GetString(CSettings::SETTING_LOCALE_LANGUAGE); - break; - default: - return false; - } - return GetAddon(setting, addon, type); -} - -bool CAddonMgr::SetDefault(const TYPE &type, const std::string &addonID) -{ - switch (type) - { - case ADDON_VIZ: - CSettings::GetInstance().SetString(CSettings::SETTING_MUSICPLAYER_VISUALISATION, addonID); - break; - case ADDON_SCREENSAVER: - CSettings::GetInstance().SetString(CSettings::SETTING_SCREENSAVER_MODE, addonID); - break; - case ADDON_SCRAPER_ALBUMS: - CSettings::GetInstance().SetString(CSettings::SETTING_MUSICLIBRARY_ALBUMSSCRAPER, addonID); - break; - case ADDON_SCRAPER_ARTISTS: - CSettings::GetInstance().SetString(CSettings::SETTING_MUSICLIBRARY_ARTISTSSCRAPER, addonID); - break; - case ADDON_SCRAPER_MOVIES: - CSettings::GetInstance().SetString(CSettings::SETTING_SCRAPERS_MOVIESDEFAULT, addonID); - break; - case ADDON_SCRAPER_MUSICVIDEOS: - CSettings::GetInstance().SetString(CSettings::SETTING_SCRAPERS_MUSICVIDEOSDEFAULT, addonID); - break; - case ADDON_SCRAPER_TVSHOWS: - CSettings::GetInstance().SetString(CSettings::SETTING_SCRAPERS_TVSHOWSDEFAULT, addonID); - break; - case ADDON_RESOURCE_LANGUAGE: - CSettings::GetInstance().SetString(CSettings::SETTING_LOCALE_LANGUAGE, addonID); - break; - case ADDON_SCRIPT_WEATHER: - CSettings::GetInstance().SetString(CSettings::SETTING_WEATHER_ADDON, addonID); - break; - case ADDON_SKIN: - CSettings::GetInstance().SetString(CSettings::SETTING_LOOKANDFEEL_SKIN, addonID); - break; - case ADDON_RESOURCE_UISOUNDS: - CSettings::GetInstance().SetString(CSettings::SETTING_LOOKANDFEEL_SOUNDSKIN, addonID); - break; - default: - return false; - } - - return true; -} - bool CAddonMgr::FindAddons() { bool result = false; @@ -1204,6 +1122,11 @@ bool CAddonMgr::AddonsFromRepoXML(const CRepository::DirInfo& repo, const std::s return true; } +bool CAddonMgr::ServicesHasStarted() const +{ + CSingleLock lock(m_critSection); + return m_serviceSystemStarted; +} bool CAddonMgr::StartServices(const bool beforelogin) { @@ -1225,6 +1148,9 @@ bool CAddonMgr::StartServices(const bool beforelogin) } } + CSingleLock lock(m_critSection); + m_serviceSystemStarted = true; + return ret; } @@ -1248,6 +1174,31 @@ void CAddonMgr::StopServices(const bool onlylogin) } } +bool CAddonMgr::IsCompatible(const IAddon& addon) +{ + for (const auto& dependencyInfo : addon.GetDeps()) + { + const auto& optional = dependencyInfo.second.second; + if (!optional) + { + const auto& dependencyId = dependencyInfo.first; + const auto& version = dependencyInfo.second.first; + + // Intentionally only check the xbmc.* and kodi.* magic dependencies. Everything else will + // not be missing anyway, unless addon was installed in an unsupported way. + if (StringUtils::StartsWith(dependencyId, "xbmc.") || + StringUtils::StartsWith(dependencyId, "kodi.")) + { + AddonPtr dependency; + bool haveAddon = GetAddon(dependencyId, dependency); + if (!haveAddon || !dependency->MeetsVersion(version)) + return false; + } + } + } + return true; +} + int cp_to_clog(cp_log_severity_t lvl) { if (lvl >= CP_LOG_ERROR) diff --git a/xbmc/addons/AddonManager.h b/xbmc/addons/AddonManager.h index 7a2835cc56..3eb857631f 100644 --- a/xbmc/addons/AddonManager.h +++ b/xbmc/addons/AddonManager.h @@ -83,9 +83,6 @@ namespace ADDON bool RegisterAddonMgrCallback(TYPE type, IAddonMgrCallback* cb); void UnregisterAddonMgrCallback(TYPE type); - /* Addon access */ - bool GetDefault(const TYPE &type, AddonPtr &addon); - bool SetDefault(const TYPE &type, const std::string &addonID); /*! \brief Retrieve a specific addon (of a specific type) \param id the id of the addon to retrieve. \param addon [out] the retrieved addon pointer - only use if the function returns true. @@ -245,6 +242,10 @@ namespace ADDON */ void StopServices(const bool onlylogin); + bool ServicesHasStarted() const; + + bool IsCompatible(const IAddon& addon); + static AddonPtr Factory(const cp_plugin_info_t* plugin, TYPE type); static bool Factory(const cp_plugin_info_t* plugin, TYPE type, CAddonBuilder& builder); static void FillCpluffMetadata(const cp_plugin_info_t* plugin, CAddonBuilder& builder); @@ -273,6 +274,7 @@ namespace ADDON CEventSource<AddonEvent> m_events; std::set<std::string> m_systemAddons; std::set<std::string> m_optionalAddons; + bool m_serviceSystemStarted; }; }; /* namespace ADDON */ diff --git a/xbmc/addons/AddonSystemSettings.cpp b/xbmc/addons/AddonSystemSettings.cpp index a8dc72d9fe..fccc680bd1 100644 --- a/xbmc/addons/AddonSystemSettings.cpp +++ b/xbmc/addons/AddonSystemSettings.cpp @@ -19,11 +19,13 @@ */ #include "addons/AddonManager.h" +#include "addons/AddonInstaller.h" #include "addons/AddonSystemSettings.h" #include "addons/RepositoryUpdater.h" #include "guilib/GUIWindowManager.h" #include "messaging/helpers/DialogHelper.h" #include "settings/Settings.h" +#include "utils/log.h" namespace ADDON @@ -61,4 +63,108 @@ void CAddonSystemSettings::OnSettingChanged(const CSetting* setting) } } +static const std::map<ADDON::TYPE, std::string> settingMap = { + {ADDON_VIZ, CSettings::SETTING_MUSICPLAYER_VISUALISATION}, + {ADDON_SCREENSAVER, CSettings::SETTING_SCREENSAVER_MODE}, + {ADDON_SCRAPER_ALBUMS, CSettings::SETTING_MUSICLIBRARY_ALBUMSSCRAPER}, + {ADDON_SCRAPER_ARTISTS, CSettings::SETTING_MUSICLIBRARY_ARTISTSSCRAPER}, + {ADDON_SCRAPER_MOVIES, CSettings::SETTING_SCRAPERS_MOVIESDEFAULT}, + {ADDON_SCRAPER_MUSICVIDEOS, CSettings::SETTING_SCRAPERS_MUSICVIDEOSDEFAULT}, + {ADDON_SCRAPER_TVSHOWS, CSettings::SETTING_SCRAPERS_TVSHOWSDEFAULT}, + {ADDON_WEB_INTERFACE, CSettings::SETTING_SERVICES_WEBSKIN}, + {ADDON_RESOURCE_LANGUAGE, CSettings::SETTING_LOCALE_LANGUAGE}, + {ADDON_SCRIPT_WEATHER, CSettings::SETTING_WEATHER_ADDON}, + {ADDON_SKIN, CSettings::SETTING_LOOKANDFEEL_SKIN}, + {ADDON_RESOURCE_UISOUNDS, CSettings::SETTING_LOOKANDFEEL_SOUNDSKIN}, +}; + +bool CAddonSystemSettings::GetActive(const TYPE& type, AddonPtr& addon) +{ + auto it = settingMap.find(type); + if (it != settingMap.end()) + { + auto settingValue = CSettings::GetInstance().GetString(it->second); + return CAddonMgr::GetInstance().GetAddon(settingValue, addon, type); + } + return false; +} + +bool CAddonSystemSettings::SetActive(const TYPE& type, const std::string& addonID) +{ + auto it = settingMap.find(type); + if (it != settingMap.end()) + { + CSettings::GetInstance().SetString(it->second, addonID); + return true; + } + return false; +} + +bool CAddonSystemSettings::IsActive(const IAddon& addon) +{ + AddonPtr active; + return GetActive(addon.Type(), active) && active->ID() == addon.ID(); +} + +bool CAddonSystemSettings::UnsetActive(const AddonPtr& addon) +{ + auto it = settingMap.find(addon->Type()); + if (it == settingMap.end()) + return true; + + auto setting = static_cast<CSettingString*>(CSettings::GetInstance().GetSetting(it->second)); + if (setting->GetValue() != addon->ID()) + return true; + + if (setting->GetDefault() == addon->ID()) + return false; // Cant unset defaults + + setting->Reset(); + return true; +} + + +std::vector<std::string> CAddonSystemSettings::MigrateAddons() +{ + auto getIncompatible = [](){ + VECADDONS incompatible; + CAddonMgr::GetInstance().GetAddons(incompatible); + incompatible.erase(std::remove_if(incompatible.begin(), incompatible.end(), + [](const AddonPtr a){ return CAddonMgr::GetInstance().IsCompatible(*a); }), incompatible.end()); + return incompatible; + }; + + if (getIncompatible().empty()) + return std::vector<std::string>(); + + if (CSettings::GetInstance().GetInt(CSettings::SETTING_ADDONS_AUTOUPDATES) == AUTO_UPDATES_ON) + { + if (CRepositoryUpdater::GetInstance().CheckForUpdates()) + CRepositoryUpdater::GetInstance().Await(); + + CLog::Log(LOGINFO, "ADDON: waiting for add-ons to update..."); + CAddonInstaller::GetInstance().InstallUpdates(); + } + + auto incompatible = getIncompatible(); + for (const auto& addon : incompatible) + CLog::Log(LOGNOTICE, "ADDON: %s version %s is incompatible", addon->ID().c_str(), addon->Version().asString().c_str()); + + std::vector<std::string> changed; + for (const auto& addon : incompatible) + { + if (!UnsetActive(addon)) + { + CLog::Log(LOGWARNING, "ADDON: failed to unset %s", addon->ID().c_str()); + continue; + } + if (!CAddonMgr::GetInstance().DisableAddon(addon->ID())) + { + CLog::Log(LOGWARNING, "ADDON: failed to disable %s", addon->ID().c_str()); + } + changed.push_back(addon->Name()); + } + + return changed; +} } diff --git a/xbmc/addons/AddonSystemSettings.h b/xbmc/addons/AddonSystemSettings.h index af67d8c36f..42a5345aad 100644 --- a/xbmc/addons/AddonSystemSettings.h +++ b/xbmc/addons/AddonSystemSettings.h @@ -19,8 +19,9 @@ * */ +#include "addons/IAddon.h" #include "settings/lib/ISettingCallback.h" - +#include <string> namespace ADDON { @@ -36,6 +37,21 @@ public: void OnSettingAction(const CSetting* setting) override; void OnSettingChanged(const CSetting* setting) override; + bool GetActive(const TYPE& type, AddonPtr& addon); + bool SetActive(const TYPE& type, const std::string& addonID); + bool IsActive(const IAddon& addon); + + /*! + * Attempt to unset addon as active. Returns true if addon is no longer active, + * false if it could not be unset (e.g. if the addon is the default) + */ + bool UnsetActive(const AddonPtr& addon); + + /*! + * Attempt to migrate installed addons. Returns a list of addons that was modified. + */ + std::vector<std::string> MigrateAddons(); + private: CAddonSystemSettings() = default; CAddonSystemSettings(const CAddonSystemSettings&) = default; diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp index 81f1104a06..167bcf9a2a 100644 --- a/xbmc/addons/GUIDialogAddonInfo.cpp +++ b/xbmc/addons/GUIDialogAddonInfo.cpp @@ -367,7 +367,7 @@ void CGUIDialogAddonInfo::OnSelect() if (CanOpen() || CanRun()) CBuiltins::GetInstance().Execute("RunAddon(" + m_localAddon->ID() + ")"); else if (CanUse()) - CAddonMgr::GetInstance().SetDefault(m_localAddon->Type(), m_localAddon->ID()); + CAddonSystemSettings::GetInstance().SetActive(m_localAddon->Type(), m_localAddon->ID()); } bool CGUIDialogAddonInfo::CanOpen() const diff --git a/xbmc/addons/GUIWindowAddonBrowser.cpp b/xbmc/addons/GUIWindowAddonBrowser.cpp index b2909d766a..68cb844cf9 100644 --- a/xbmc/addons/GUIWindowAddonBrowser.cpp +++ b/xbmc/addons/GUIWindowAddonBrowser.cpp @@ -165,7 +165,8 @@ class UpdateAddons : public IRunnable { virtual void Run() { - CAddonInstaller::GetInstance().InstallUpdates(true); + for (const auto& addon : CAddonMgr::GetInstance().GetAvailableUpdates()) + CAddonInstaller::GetInstance().InstallOrUpdate(addon->ID()); } }; diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp index cb6bc19738..e64a3665c1 100644 --- a/xbmc/addons/Repository.cpp +++ b/xbmc/addons/Repository.cpp @@ -258,57 +258,47 @@ bool CRepositoryUpdateJob::DoWork() database.UpdateRepositoryContent(m_repo->ID(), m_repo->Version(), newChecksum, addons); - //Update broken status - database.BeginMultipleExecute(); + //Notify about broken status changes for (const auto& addon : addons) { AddonPtr localAddon; - CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon); + if (!CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon)) + continue; if (localAddon && localAddon->Version() > addon->Version()) - //We have a newer verison locally + //We have a newer version locally continue; + AddonPtr oldAddon; + database.GetAddon(addon->ID(), oldAddon); + if (database.GetAddonVersion(addon->ID()).first > addon->Version()) //Newer version in db (ie. in a different repo) continue; std::string broken = addon->Broken(); - bool depsMet = CAddonInstaller::GetInstance().CheckDependencies(addon); - if (!depsMet && broken.empty()) - broken = "DEPSNOTMET"; - - if (localAddon) + bool isBroken = !addon->Broken().empty(); + bool isBrokenInDb = oldAddon && !oldAddon->Broken().empty(); + if (isBroken && !isBrokenInDb) { - bool brokenInDb = database.IsAddonBroken(addon->ID()); - if (!broken.empty() && !brokenInDb) - { - //newly broken - int line = 24096; - if (broken == "DEPSNOTMET") - line = 24104; - if (HELPERS::ShowYesNoDialogLines(CVariant{addon->Name()}, CVariant{line}, CVariant{24097}, CVariant{""}) - == DialogResponse::YES) - { - CAddonMgr::GetInstance().DisableAddon(addon->ID()); - } - - CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' marked broken. reason: \"%s\"", - m_repo->ID().c_str(), addon->ID().c_str(), broken.c_str()); - - CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24096))); - } - else if (broken.empty() && brokenInDb) + //newly broken + if (HELPERS::ShowYesNoDialogLines(CVariant{addon->Name()}, CVariant{24096}, CVariant{24097}, CVariant{""}) + == DialogResponse::YES) { - //Unbroken - CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' unbroken", - m_repo->ID().c_str(), addon->ID().c_str()); + CAddonMgr::GetInstance().DisableAddon(addon->ID()); } - } - //Update broken status - database.BreakAddon(addon->ID(), broken); + CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' marked broken. reason: \"%s\"", + m_repo->ID().c_str(), addon->ID().c_str(), broken.c_str()); + + CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24096))); + } + else if (!isBroken && isBrokenInDb) + { + //Unbroken + CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' unbroken", + m_repo->ID().c_str(), addon->ID().c_str()); + } } - database.CommitMultipleExecute(); return true; } diff --git a/xbmc/addons/RepositoryUpdater.cpp b/xbmc/addons/RepositoryUpdater.cpp index 41bc15c496..357f4f8af0 100644 --- a/xbmc/addons/RepositoryUpdater.cpp +++ b/xbmc/addons/RepositoryUpdater.cpp @@ -64,9 +64,10 @@ void CRepositoryUpdater::OnJobComplete(unsigned int jobID, bool success, CJob* j CLog::Log(LOGDEBUG, "CRepositoryUpdater: done."); m_doneEvent.Set(); + VECADDONS updates = CAddonMgr::GetInstance().GetAvailableUpdates(); + if (CSettings::GetInstance().GetInt(CSettings::SETTING_ADDONS_AUTOUPDATES) == AUTO_UPDATES_NOTIFY) { - VECADDONS updates = CAddonMgr::GetInstance().GetAvailableUpdates(); if (!updates.empty()) { if (updates.size() == 1) @@ -84,7 +85,13 @@ void CRepositoryUpdater::OnJobComplete(unsigned int jobID, bool success, CJob* j } if (CSettings::GetInstance().GetInt(CSettings::SETTING_ADDONS_AUTOUPDATES) == AUTO_UPDATES_ON) - CAddonInstaller::GetInstance().InstallUpdates(); + { + for (const auto& addon : updates) + { + if (!CAddonMgr::GetInstance().IsBlacklisted(addon->ID())) + CAddonInstaller::GetInstance().InstallOrUpdate(addon->ID()); + } + } ScheduleUpdate(); diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp index fa20233d42..f5b5f1f67b 100644 --- a/xbmc/addons/Skin.cpp +++ b/xbmc/addons/Skin.cpp @@ -369,12 +369,13 @@ const INFO::CSkinVariableString* CSkinInfo::CreateSkinVariable(const std::string void CSkinInfo::OnPreInstall() { - if (IsInUse()) - CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, "UnloadSkin"); } void CSkinInfo::OnPostInstall(bool update, bool modal) { + if (!g_SkinInfo) + return; + if (IsInUse() || (!update && !modal && HELPERS::ShowYesNoDialogText(CVariant{Name()}, CVariant{24099}) == DialogResponse::YES)) { @@ -385,7 +386,7 @@ void CSkinInfo::OnPostInstall(bool update, bool modal) toast->Close(true); } if (CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKIN) == ID()) - CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, "ReloadSkin"); + CApplicationMessenger::GetInstance().PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, "ReloadSkin"); else CSettings::GetInstance().SetString(CSettings::SETTING_LOOKANDFEEL_SKIN, ID()); } @@ -393,6 +394,9 @@ void CSkinInfo::OnPostInstall(bool update, bool modal) void CSkinInfo::SettingOptionsSkinColorsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, void *data) { + if (!g_SkinInfo) + return; + std::string settingValue = ((const CSettingString*)setting)->GetValue(); // Remove the .xml extension from the Themes if (URIUtils::HasExtension(settingValue, ".xml")) @@ -434,6 +438,9 @@ void CSkinInfo::SettingOptionsSkinColorsFiller(const CSetting *setting, std::vec void CSkinInfo::SettingOptionsSkinFontsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, void *data) { + if (!g_SkinInfo) + return; + std::string settingValue = ((const CSettingString*)setting)->GetValue(); bool currentValueSet = false; std::string strPath = g_SkinInfo->GetSkinPath("Font.xml"); @@ -512,6 +519,9 @@ void CSkinInfo::SettingOptionsSkinThemesFiller(const CSetting *setting, std::vec void CSkinInfo::SettingOptionsStartupWindowsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t, void *data) { + if (!g_SkinInfo) + return; + int settingValue = ((const CSettingInt *)setting)->GetValue(); current = -1; diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp index c6a7f569a8..af5bf93116 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp @@ -33,7 +33,7 @@ using namespace ActiveAE; CActiveAEResampleFFMPEG::CActiveAEResampleFFMPEG() { m_pContext = NULL; - m_loaded = true; + m_doesResample = false; } CActiveAEResampleFFMPEG::~CActiveAEResampleFFMPEG() @@ -43,9 +43,6 @@ CActiveAEResampleFFMPEG::~CActiveAEResampleFFMPEG() bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality, bool force_resample) { - if (!m_loaded) - return false; - m_dst_chan_layout = dst_chan_layout; m_dst_channels = dst_channels; m_dst_rate = dst_rate; @@ -59,6 +56,9 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i m_src_bits = src_bits; m_src_dither_bits = src_dither; + if (m_src_rate != m_dst_rate) + m_doesResample = true; + if (m_dst_chan_layout == 0) m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); if (m_src_chan_layout == 0) @@ -186,12 +186,16 @@ int CActiveAEResampleFFMPEG::Resample(uint8_t **dst_buffer, int dst_samples, uin { delta = (dst_samples*ratio-dst_samples)*m_dst_rate/m_src_rate; distance = dst_samples*m_dst_rate/m_src_rate; + m_doesResample = true; } - if (swr_set_compensation(m_pContext, delta, distance) < 0) + if (m_doesResample) { - CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Resample - set compensation failed"); - return -1; + if (swr_set_compensation(m_pContext, delta, distance) < 0) + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Resample - set compensation failed"); + return -1; + } } int ret = swr_convert(m_pContext, dst_buffer, dst_samples, (const uint8_t**)src_buffer, src_samples); diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h index 372c8eed8a..fa65c7789c 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.h @@ -50,6 +50,7 @@ public: protected: bool m_loaded; + bool m_doesResample; uint64_t m_src_chan_layout, m_dst_chan_layout; int m_src_rate, m_dst_rate; int m_src_channels, m_dst_channels; diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp index b54a85a0ba..dbba74277a 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp @@ -69,10 +69,10 @@ static const enum AEChannel layoutsList[][16] = {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Quad {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BC, AE_CH_NULL}, // Surround {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_NULL}, // Standard 5.1 + {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // 5.1 wide (obsolete) {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Standard 7.1 /* Less common configurations */ {AE_CH_FL, AE_CH_FR, AE_CH_LFE, AE_CH_NULL}, // 2.1 - {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // 5.1 wide (obsolete) {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_FLOC,AE_CH_FROC,AE_CH_NULL}, // 7.1 wide (obsolete) /* Exotic configurations */ {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_NULL}, // 3 front speakers diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h index 90073afa4a..7bc005bce2 100644 --- a/xbmc/cores/IPlayer.h +++ b/xbmc/cores/IPlayer.h @@ -224,7 +224,9 @@ enum ViewMode { ViewModeStretch16x9, ViewModeOriginal, ViewModeCustom, - ViewModeStretch16x9Nonlin + ViewModeStretch16x9Nonlin, + ViewModeZoom120Width, + ViewModeZoom110Width }; class IPlayer diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp index 5dadf82c2a..f9b4138162 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp @@ -1599,7 +1599,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) am_private->gcodec.param = (void*)(EXTERNAL_PTS | SYNC_OUTSIDE); break; } - am_private->gcodec.param = (void *)((unsigned int)am_private->gcodec.param | (am_private->video_rotation_degree << 16)); + am_private->gcodec.param = (void *)((std::uintptr_t)am_private->gcodec.param | (am_private->video_rotation_degree << 16)); // translate from generic to firemware version dependent m_dll->codec_init_para(&am_private->gcodec, &am_private->vcodec); diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp index 23bcb080fa..8460e27865 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -646,7 +646,8 @@ AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() bool hasCookies = false; for(std::map<std::string, std::string>::const_iterator it = protocolOptions.begin(); it != protocolOptions.end(); ++it) { - std::string name = it->first; StringUtils::ToLower(name); + std::string name = it->first; + StringUtils::ToLower(name); const std::string &value = it->second; if (name == "seekable") @@ -660,24 +661,30 @@ AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() } else if (name == "cookie") { - av_dict_set(&options, "cookies", value.c_str(), 0); CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() adding ffmpeg option 'cookies: %s'", value.c_str()); + headers.append(it->first).append(": ").append(value).append("\r\n"); hasCookies = true; } // other standard headers (see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) are appended as actual headers else if (name == "accept" || name == "accept-language" || name == "accept-datetime" || - name == "authorization" || name == "cache-control" || name == "connection" || name == "content-md5" || - name == "date" || name == "expect" || name == "forwarded" || name == "from" || name == "if-match" || - name == "if-modified-since" || name == "if-none-match" || name == "if-range" || name == "if-unmodified-since" || name == "max-forwards" || - name == "origin" || name == "pragma" || name == "range" || name == "referer" || name == "te" || name == "upgrade" || - name == "via" || name == "warning" || name == "x-requested-with" || name == "dnt" || name == "x-forwarded-for" || name == "x-forwarded-host" || - name == "x-forwarded-proto" || name == "front-end-https" || name == "x-http-method-override" || name == "x-att-deviceid" || - name == "x-wap-profile" || name == "x-uidh" || name == "x-csrf-token" || name == "x-request-id" || name == "x-correlation-id") + name == "authorization" || name == "cache-control" || name == "connection" || name == "content-md5" || + name == "date" || name == "expect" || name == "forwarded" || name == "from" || name == "if-match" || + name == "if-modified-since" || name == "if-none-match" || name == "if-range" || name == "if-unmodified-since" || + name == "max-forwards" || name == "origin" || name == "pragma" || name == "range" || name == "referer" || + name == "te" || name == "upgrade" || name == "via" || name == "warning" || name == "x-requested-with" || + name == "dnt" || name == "x-forwarded-for" || name == "x-forwarded-host" || name == "x-forwarded-proto" || + name == "front-end-https" || name == "x-http-method-override" || name == "x-att-deviceid" || + name == "x-wap-profile" || name == "x-uidh" || name == "x-csrf-token" || name == "x-request-id" || + name == "x-correlation-id") { if (name == "authorization") + { CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() adding custom header option '%s: ***********'", it->first.c_str()); + } else + { CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() adding custom header option '%s: %s'", it->first.c_str(), value.c_str()); + } headers.append(it->first).append(": ").append(value).append("\r\n"); } // we don't add blindly all options to headers anymore @@ -689,8 +696,10 @@ AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromInput() } } if (!hasUserAgent) + { // set default xbmc user-agent. av_dict_set(&options, "user-agent", g_advancedSettings.m_userAgent.c_str(), 0); + } if (!headers.empty()) av_dict_set(&options, "headers", headers.c_str(), 0); diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp index 276a65fd7b..ba1bc8fcd0 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp @@ -145,15 +145,18 @@ CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer { if (finalFileitem.ContentLookup()) { - XFILE::CCurlFile url; + CURL origUrl(finalFileitem.GetURL()); + XFILE::CCurlFile curlFile; // try opening the url to resolve all redirects if any try { - if (url.Open(finalFileitem.GetURL())) + if (curlFile.Open(finalFileitem.GetURL())) { - finalFileitem.SetPath(url.GetURL()); + CURL finalUrl(curlFile.GetURL()); + finalUrl.SetProtocolOptions(origUrl.GetProtocolOptions()); + finalFileitem.SetPath(finalUrl.Get()); } - url.Close(); + curlFile.Close(); } catch (XFILE::CRedirectException *pRedirectEx) { diff --git a/xbmc/cores/VideoPlayer/VideoPlayerRadioRDS.cpp b/xbmc/cores/VideoPlayer/VideoPlayerRadioRDS.cpp index 52c6799b5e..dd5082e964 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerRadioRDS.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerRadioRDS.cpp @@ -1730,9 +1730,6 @@ unsigned int CDVDRadioRDSData::DecodeTDC(uint8_t *msgElement, unsigned int len) void CDVDRadioRDSData::SendTMCSignal(unsigned int flags, uint8_t *data) { - if (!CSettings::GetInstance().GetBool("pvrplayback.sendrdstrafficmsg")) - return; - if (!(flags & 0x80) && (memcmp(data, m_TMC_LastData, 5) == 0)) return; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp index f18c671d90..f9b3bfb4eb 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/BaseRenderer.cpp @@ -428,7 +428,7 @@ void CBaseRenderer::ManageRenderArea() void CBaseRenderer::SetViewMode(int viewMode) { - if (viewMode < ViewModeNormal || viewMode > ViewModeStretch16x9Nonlin) + if (viewMode < ViewModeNormal || viewMode > ViewModeZoom110Width) viewMode = ViewModeNormal; CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode = viewMode; @@ -537,6 +537,18 @@ void CBaseRenderer::SetViewMode(int viewMode) CDisplaySettings::GetInstance().SetNonLinearStretched(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_CustomNonLinStretch); CDisplaySettings::GetInstance().SetVerticalShift(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_CustomVerticalShift); } + else if (CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode == ViewModeZoom120Width) + { + float fitHeightZoom = sourceFrameRatio * screenHeight / (info.fPixelRatio * screenWidth); + CDisplaySettings::GetInstance().SetPixelRatio(1.0f); + CDisplaySettings::GetInstance().SetZoomAmount(fitHeightZoom < 1.0f ? 1.0f : (fitHeightZoom > 1.2f ? 1.2f : fitHeightZoom)); + } + else if (CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode == ViewModeZoom110Width) + { + float fitHeightZoom = sourceFrameRatio * screenHeight / (info.fPixelRatio * screenWidth); + CDisplaySettings::GetInstance().SetPixelRatio(1.0f); + CDisplaySettings::GetInstance().SetZoomAmount(fitHeightZoom < 1.0f ? 1.0f : (fitHeightZoom > 1.1f ? 1.1f : fitHeightZoom)); + } else // if (CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode == ViewModeNormal) { CDisplaySettings::GetInstance().SetPixelRatio(1.0); diff --git a/xbmc/epg/GUIEPGGridContainer.cpp b/xbmc/epg/GUIEPGGridContainer.cpp index 96c7bec2da..8cfa281585 100644 --- a/xbmc/epg/GUIEPGGridContainer.cpp +++ b/xbmc/epg/GUIEPGGridContainer.cpp @@ -53,6 +53,7 @@ CGUIEPGGridContainer::CGUIEPGGridContainer(int parentID, int controlID, float po m_programmeLayout(nullptr), m_focusedProgrammeLayout(nullptr), m_rulerLayout(nullptr), + m_pageControl(0), m_rulerUnit(rulerUnit), m_channelsPerPage(0), m_programmesPerPage(0), @@ -105,6 +106,7 @@ CGUIEPGGridContainer::CGUIEPGGridContainer(const CGUIEPGGridContainer &other) m_programmeLayout(other.m_programmeLayout), m_focusedProgrammeLayout(other.m_focusedProgrammeLayout), m_rulerLayout(other.m_rulerLayout), + m_pageControl(other.m_pageControl), m_rulerUnit(other.m_rulerUnit), m_channelsPerPage(other.m_channelsPerPage), m_programmesPerPage(other.m_programmesPerPage), @@ -147,19 +149,38 @@ CGUIEPGGridContainer::CGUIEPGGridContainer(const CGUIEPGGridContainer &other) { } +void CGUIEPGGridContainer::SetPageControl(int id) +{ + m_pageControl = id; +} + void CGUIEPGGridContainer::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) { ValidateOffset(); if (m_bInvalidated) + { UpdateLayout(); + if (m_pageControl && m_gridModel->ChannelItemsSize()) + { + CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), m_pageControl, m_channelsPerPage, m_gridModel->ChannelItemsSize()); + SendWindowMessage(msg); + } + } + UpdateScrollOffset(currentTime); ProcessChannels(currentTime, dirtyregions); ProcessRuler(currentTime, dirtyregions); ProcessProgrammeGrid(currentTime, dirtyregions); ProcessProgressIndicator(currentTime, dirtyregions); + if (m_pageControl && m_gridModel->ChannelItemsSize()) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), m_pageControl, MathUtils::round_int(m_channelScrollOffset / m_channelHeight)); + SendWindowMessage(msg); + } + CGUIControl::Process(currentTime, dirtyregions); } @@ -453,6 +474,14 @@ bool CGUIEPGGridContainer::OnMessage(CGUIMessage& message) message.SetParam1(GetSelectedItem()); return true; + case GUI_MSG_PAGE_CHANGE: + if (message.GetSenderId() == m_pageControl && IsVisible()) + { + ScrollToChannelOffset(message.GetParam1()); + return true; + } + break; + case GUI_MSG_LABEL_BIND: UpdateItems(); return true; @@ -1038,10 +1067,16 @@ std::string CGUIEPGGridContainer::GetLabel(int info) const switch (info) { case CONTAINER_NUM_PAGES: - label = StringUtils::Format("%u", (m_gridModel->ChannelItemsSize() + m_channelsPerPage - 1) / m_channelsPerPage); + if (m_channelsPerPage > 0) + label = StringUtils::Format("%u", (m_gridModel->ChannelItemsSize() + m_channelsPerPage - 1) / m_channelsPerPage); + else + label = StringUtils::Format("%u", 0); break; case CONTAINER_CURRENT_PAGE: - label = StringUtils::Format("%u", 1 + (m_channelCursor + m_channelOffset) / m_channelsPerPage ); + if (m_channelsPerPage > 0) + label = StringUtils::Format("%u", 1 + (m_channelCursor + m_channelOffset) / m_channelsPerPage); + else + label = StringUtils::Format("%u", 1); break; case CONTAINER_POSITION: label = StringUtils::Format("%i", 1 + m_channelCursor + m_channelOffset); @@ -1330,7 +1365,7 @@ void CGUIEPGGridContainer::GoToEnd() int blocksEnd = 0; // the end block of the last epg element for the selected channel int blocksStart = 0; // the start block of the last epg element for the selected channel int blockOffset = 0; // the block offset to scroll to - for (int blockIndex = m_gridModel->GetBlockCount(); blockIndex >= 0 && (!blocksEnd || !blocksStart); blockIndex--) + for (int blockIndex = m_gridModel->GetBlockCount() - 1; blockIndex >= 0 && (!blocksEnd || !blocksStart); blockIndex--) { if (!blocksEnd && m_gridModel->GetGridItem(m_channelCursor + m_channelOffset, blockIndex)) blocksEnd = blockIndex; diff --git a/xbmc/epg/GUIEPGGridContainer.h b/xbmc/epg/GUIEPGGridContainer.h index e867f16834..55f3af91c8 100644 --- a/xbmc/epg/GUIEPGGridContainer.h +++ b/xbmc/epg/GUIEPGGridContainer.h @@ -43,6 +43,8 @@ namespace EPG virtual CGUIEPGGridContainer *Clone() const { return new CGUIEPGGridContainer(*this); } + void SetPageControl(int id); + virtual bool OnAction(const CAction &action); virtual void OnDown(); virtual void OnUp(); @@ -139,6 +141,8 @@ namespace EPG CGUIListItemLayout *m_focusedProgrammeLayout; CGUIListItemLayout *m_rulerLayout; + int m_pageControl; + void GetChannelCacheOffsets(int &cacheBefore, int &cacheAfter); void GetProgrammeCacheOffsets(int &cacheBefore, int &cacheAfter); diff --git a/xbmc/filesystem/AddonsDirectory.cpp b/xbmc/filesystem/AddonsDirectory.cpp index fc252a406d..63e384fd14 100644 --- a/xbmc/filesystem/AddonsDirectory.cpp +++ b/xbmc/filesystem/AddonsDirectory.cpp @@ -623,8 +623,6 @@ void CAddonsDirectory::GenerateAddonListing(const CURL &path, pItem->SetProperty("Addon.Status", g_localizeStrings.Get(24023)); if (hasUpdate) pItem->SetProperty("Addon.Status", g_localizeStrings.Get(24068)); - if (addon->Broken() == "DEPSNOTMET") - pItem->SetProperty("Addon.Status", g_localizeStrings.Get(24049)); else if (!addon->Broken().empty()) pItem->SetProperty("Addon.Status", g_localizeStrings.Get(24098)); diff --git a/xbmc/guilib/GUIControlFactory.cpp b/xbmc/guilib/GUIControlFactory.cpp index 53f8fe1c2b..91cf5534bb 100644 --- a/xbmc/guilib/GUIControlFactory.cpp +++ b/xbmc/guilib/GUIControlFactory.cpp @@ -1338,10 +1338,12 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl break; case CGUIControl::GUICONTAINER_EPGGRID: { - control = new CGUIEPGGridContainer(parentID, id, posX, posY, width, height, scrollTime, preloadItems, timeBlocks, rulerUnit, textureProgressIndicator); - ((CGUIEPGGridContainer *)control)->LoadLayout(pControlNode); - ((CGUIEPGGridContainer *)control)->SetRenderOffset(offset); - ((CGUIEPGGridContainer *)control)->SetType(viewType, viewLabel); + CGUIEPGGridContainer *epgGridContainer = new CGUIEPGGridContainer(parentID, id, posX, posY, width, height, scrollTime, preloadItems, timeBlocks, rulerUnit, textureProgressIndicator); + control = epgGridContainer; + epgGridContainer->LoadLayout(pControlNode); + epgGridContainer->SetRenderOffset(offset); + epgGridContainer->SetType(viewType, viewLabel); + epgGridContainer->SetPageControl(pageControl); } break; case CGUIControl::GUICONTAINER_FIXEDLIST: diff --git a/xbmc/guilib/GUIVisualisationControl.cpp b/xbmc/guilib/GUIVisualisationControl.cpp index cde54c17dc..e4d8d5e578 100644 --- a/xbmc/guilib/GUIVisualisationControl.cpp +++ b/xbmc/guilib/GUIVisualisationControl.cpp @@ -23,6 +23,7 @@ #include "GUIUserMessages.h" #include "Application.h" #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "addons/Visualisation.h" #include "utils/log.h" #include "input/Key.h" @@ -100,7 +101,7 @@ void CGUIVisualisationControl::Process(unsigned int currentTime, CDirtyRegionLis if (!m_addon && !m_bAttemptedLoad) { AddonPtr addon; - if (ADDON::CAddonMgr::GetInstance().GetDefault(ADDON_VIZ, addon)) + if (ADDON::CAddonSystemSettings::GetInstance().GetActive(ADDON_VIZ, addon)) { m_addon = std::dynamic_pointer_cast<CVisualisation>(addon); if (m_addon) diff --git a/xbmc/interfaces/builtins/AddonBuiltins.cpp b/xbmc/interfaces/builtins/AddonBuiltins.cpp index 18b112dd2d..5b5eb7ef8c 100644 --- a/xbmc/interfaces/builtins/AddonBuiltins.cpp +++ b/xbmc/interfaces/builtins/AddonBuiltins.cpp @@ -24,6 +24,7 @@ #include "addons/AddonManager.h" #include "addons/AddonInstaller.h" +#include "addons/AddonSystemSettings.h" #include "addons/GUIDialogAddonSettings.h" #include "addons/GUIWindowAddonBrowser.h" #include "addons/PluginSource.h" @@ -221,7 +222,7 @@ static int OpenDefaultSettings(const std::vector<std::string>& params) { AddonPtr addon; ADDON::TYPE type = TranslateType(params[0]); - if (CAddonMgr::GetInstance().GetDefault(type, addon)) + if (CAddonSystemSettings::GetInstance().GetActive(type, addon)) { bool changed = CGUIDialogAddonSettings::ShowAndGetInput(addon); if (type == ADDON_VIZ && changed) @@ -246,7 +247,7 @@ static int SetDefaultAddon(const std::vector<std::string>& params) if (type != ADDON_UNKNOWN && CGUIWindowAddonBrowser::SelectAddonID(type,addonID,allowNone)) { - CAddonMgr::GetInstance().SetDefault(type,addonID); + CAddonSystemSettings::GetInstance().SetActive(type, addonID); if (type == ADDON_VIZ) g_windowManager.SendMessage(GUI_MSG_VISUALISATION_RELOAD, 0, 0); } diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp index b033256b0c..59216fef18 100644 --- a/xbmc/music/MusicDatabase.cpp +++ b/xbmc/music/MusicDatabase.cpp @@ -22,6 +22,7 @@ #include "addons/Addon.h" #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "addons/Scraper.h" #include "Album.h" #include "Application.h" @@ -5689,7 +5690,7 @@ bool CMusicDatabase::GetScraperForPath(const std::string& strPath, ADDON::Scrape else { // use default scraper of the requested type ADDON::AddonPtr defaultScraper; - if (ADDON::CAddonMgr::GetInstance().GetDefault(type, defaultScraper)) + if (ADDON::CAddonSystemSettings::GetInstance().GetActive(type, defaultScraper)) { info = std::dynamic_pointer_cast<ADDON::CScraper>(defaultScraper); } @@ -5700,7 +5701,7 @@ bool CMusicDatabase::GetScraperForPath(const std::string& strPath, ADDON::Scrape if (!info) { // use default music scraper instead ADDON::AddonPtr addon; - if(ADDON::CAddonMgr::GetInstance().GetDefault(type, addon)) + if(ADDON::CAddonSystemSettings::GetInstance().GetActive(type, addon)) { info = std::dynamic_pointer_cast<ADDON::CScraper>(addon); return info != NULL; diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp index 1ebc77e248..e31e12df27 100644 --- a/xbmc/music/infoscanner/MusicInfoScanner.cpp +++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp @@ -24,6 +24,7 @@ #include <utility> #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "addons/Scraper.h" #include "dialogs/GUIDialogExtendedProgressBar.h" #include "dialogs/GUIDialogProgress.h" @@ -771,10 +772,10 @@ int CMusicInfoScanner::RetrieveMusicInfo(const std::string& strDirectory, CFileI ADDON::AddonPtr addon; ADDON::ScraperPtr albumScraper; ADDON::ScraperPtr artistScraper; - if(ADDON::CAddonMgr::GetInstance().GetDefault(ADDON::ADDON_SCRAPER_ALBUMS, addon)) + if(ADDON::CAddonSystemSettings::GetInstance().GetActive(ADDON::ADDON_SCRAPER_ALBUMS, addon)) albumScraper = std::dynamic_pointer_cast<ADDON::CScraper>(addon); - if(ADDON::CAddonMgr::GetInstance().GetDefault(ADDON::ADDON_SCRAPER_ARTISTS, addon)) + if(ADDON::CAddonSystemSettings::GetInstance().GetActive(ADDON::ADDON_SCRAPER_ARTISTS, addon)) artistScraper = std::dynamic_pointer_cast<ADDON::CScraper>(addon); // Add each album diff --git a/xbmc/music/windows/GUIWindowMusicNav.cpp b/xbmc/music/windows/GUIWindowMusicNav.cpp index 341b007574..be63b8e2b6 100644 --- a/xbmc/music/windows/GUIWindowMusicNav.cpp +++ b/xbmc/music/windows/GUIWindowMusicNav.cpp @@ -20,6 +20,7 @@ #include "GUIWindowMusicNav.h" #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "utils/FileUtils.h" #include "utils/URIUtils.h" #include "PlayListPlayer.h" @@ -706,7 +707,8 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) if (!m_musicdatabase.GetScraperForPath(path, scraper, ADDON::ScraperTypeFromContent(content))) { ADDON::AddonPtr defaultScraper; - if (ADDON::CAddonMgr::GetInstance().GetDefault(ADDON::ScraperTypeFromContent(content), defaultScraper)) + if (ADDON::CAddonSystemSettings::GetInstance().GetActive( + ADDON::ScraperTypeFromContent(content), defaultScraper)) { scraper = std::dynamic_pointer_cast<ADDON::CScraper>(defaultScraper); } diff --git a/xbmc/network/httprequesthandler/HTTPWebinterfaceHandler.cpp b/xbmc/network/httprequesthandler/HTTPWebinterfaceHandler.cpp index 0f7dcf0b61..872b6f1ab6 100644 --- a/xbmc/network/httprequesthandler/HTTPWebinterfaceHandler.cpp +++ b/xbmc/network/httprequesthandler/HTTPWebinterfaceHandler.cpp @@ -20,6 +20,7 @@ #include "HTTPWebinterfaceHandler.h" #include "addons/AddonManager.h" +#include "addons/AddonSystemSettings.h" #include "addons/Webinterface.h" #include "filesystem/Directory.h" #include "filesystem/File.h" @@ -108,7 +109,7 @@ bool CHTTPWebinterfaceHandler::ResolveAddon(const std::string &url, ADDON::Addon // determine the path within the addon path = StringUtils::Join(components, WEBSERVER_DIRECTORY_SEPARATOR); } - else if (!ADDON::CAddonMgr::GetInstance().GetDefault(ADDON::ADDON_WEB_INTERFACE, addon) || addon == NULL) + else if (!ADDON::CAddonSystemSettings::GetInstance().GetActive(ADDON::ADDON_WEB_INTERFACE, addon) || addon == NULL) return false; // get the path of the addon diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.cpp b/xbmc/pvr/windows/GUIWindowPVRBase.cpp index 4a01c99037..04eb81fbb4 100644 --- a/xbmc/pvr/windows/GUIWindowPVRBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRBase.cpp @@ -22,6 +22,7 @@ #include "GUIWindowPVRRecordings.h" #include "Application.h" +#include "addons/AddonManager.h" #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" #include "dialogs/GUIDialogKaiToast.h" #include "dialogs/GUIDialogNumeric.h" @@ -339,8 +340,14 @@ void CGUIWindowPVRBase::SetInvalid() bool CGUIWindowPVRBase::CanBeActivated() const { - // No activation if PVR is not (yet) available. - return g_PVRManager.IsStarted(); + // check if there is at least one enabled PVR add-on + if (!ADDON::CAddonMgr::GetInstance().HasAddons(ADDON::ADDON_PVRDLL)) + { + CGUIDialogOK::ShowAndGetInput(CVariant{19296}, CVariant{19272}); // No PVR add-on enabled, You need a tuner, backend software... + return false; + } + + return true; } bool CGUIWindowPVRBase::OpenChannelGroupSelectionDialog(void) diff --git a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp index ad70b8491f..610a8d10b3 100644 --- a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp @@ -70,11 +70,6 @@ void CGUIWindowPVRChannels::UnregisterObservers(void) g_EpgContainer.UnregisterObserver(this); } -bool CGUIWindowPVRChannels::CanBeActivated() const -{ - return true; -} - void CGUIWindowPVRChannels::GetContextButtons(int itemNumber, CContextButtons &buttons) { if (itemNumber < 0 || itemNumber >= m_vecItems->Size()) diff --git a/xbmc/pvr/windows/GUIWindowPVRChannels.h b/xbmc/pvr/windows/GUIWindowPVRChannels.h index a41b891156..88878ce78e 100644 --- a/xbmc/pvr/windows/GUIWindowPVRChannels.h +++ b/xbmc/pvr/windows/GUIWindowPVRChannels.h @@ -29,7 +29,6 @@ namespace PVR CGUIWindowPVRChannels(bool bRadio); virtual ~CGUIWindowPVRChannels(void) {}; - virtual bool CanBeActivated() const override; virtual bool OnMessage(CGUIMessage& message) override; virtual void GetContextButtons(int itemNumber, CContextButtons &buttons) override; virtual bool OnContextButton(int itemNumber, CONTEXT_BUTTON button) override; diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index a6b6e22ef5..bc3b0a214b 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -58,11 +58,6 @@ CGUIEPGGridContainer* CGUIWindowPVRGuide::GetGridControl() return dynamic_cast<CGUIEPGGridContainer*>(GetControl(m_viewControl.GetCurrentControl())); } -bool CGUIWindowPVRGuide::CanBeActivated() const -{ - return true; -} - void CGUIWindowPVRGuide::Init() { CGUIEPGGridContainer *epgGridContainer = GetGridControl(); diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.h b/xbmc/pvr/windows/GUIWindowPVRGuide.h index 9cfe186c72..5cf3c5365d 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.h +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.h @@ -41,7 +41,6 @@ namespace PVR CGUIWindowPVRGuide(bool bRadio); virtual ~CGUIWindowPVRGuide(void); - virtual bool CanBeActivated() const override; virtual void OnInitWindow() override; virtual void OnDeinitWindow(int nextWindowID) override; virtual bool OnMessage(CGUIMessage& message) override; diff --git a/xbmc/settings/MediaSettings.cpp b/xbmc/settings/MediaSettings.cpp index 2d9358f14d..ff466c4df0 100644 --- a/xbmc/settings/MediaSettings.cpp +++ b/xbmc/settings/MediaSettings.cpp @@ -94,7 +94,7 @@ bool CMediaSettings::Load(const TiXmlNode *settings) scalingMethod = (int)VS_SCALINGMETHOD_LINEAR; m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod; - XMLUtils::GetInt(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, ViewModeNormal, ViewModeCustom); + XMLUtils::GetInt(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, ViewModeNormal, ViewModeZoom110Width); if (!XMLUtils::GetFloat(pElement, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount, 0.5f, 2.0f)) m_defaultVideoSettings.m_CustomZoomAmount = 1.0f; if (!XMLUtils::GetFloat(pElement, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio, 0.5f, 2.0f)) diff --git a/xbmc/settings/dialogs/GUIDialogContentSettings.cpp b/xbmc/settings/dialogs/GUIDialogContentSettings.cpp index 497c781b64..de3f53c1c8 100644 --- a/xbmc/settings/dialogs/GUIDialogContentSettings.cpp +++ b/xbmc/settings/dialogs/GUIDialogContentSettings.cpp @@ -27,6 +27,7 @@ #include <limits.h> #include "GUIDialogContentSettings.h" +#include "addons/AddonSystemSettings.h" #include "addons/GUIDialogAddonSettings.h" #include "addons/GUIWindowAddonBrowser.h" #include "filesystem/AddonsDirectory.h" @@ -239,7 +240,8 @@ void CGUIDialogContentSettings::OnSettingAction(const CSetting *setting) m_content = static_cast<CONTENT_TYPE>(selected.second); AddonPtr scraperAddon; - CAddonMgr::GetInstance().GetDefault(ADDON::ScraperTypeFromContent(m_content), scraperAddon); + CAddonSystemSettings::GetInstance().GetActive(ADDON::ScraperTypeFromContent(m_content), + scraperAddon); m_scraper = std::dynamic_pointer_cast<CScraper>(scraperAddon); SetupView(); @@ -249,10 +251,13 @@ void CGUIDialogContentSettings::OnSettingAction(const CSetting *setting) else if (settingId == SETTING_SCRAPER_LIST) { ADDON::TYPE type = ADDON::ScraperTypeFromContent(m_content); - std::string selectedAddonId = m_scraper->ID(); + std::string currentScraperId; + if (m_scraper != nullptr) + currentScraperId = m_scraper->ID(); + std::string selectedAddonId = currentScraperId; if (CGUIWindowAddonBrowser::SelectAddonID(type, selectedAddonId, false) == 1 - && selectedAddonId != m_scraper->ID()) + && selectedAddonId != currentScraperId) { AddonPtr scraperAddon; CAddonMgr::GetInstance().GetAddon(selectedAddonId, scraperAddon); diff --git a/xbmc/video/CMakeLists.txt b/xbmc/video/CMakeLists.txt index 5a1c5c6c2a..9842fce0aa 100644 --- a/xbmc/video/CMakeLists.txt +++ b/xbmc/video/CMakeLists.txt @@ -10,7 +10,8 @@ set(SOURCES Bookmark.cpp VideoInfoTag.cpp VideoLibraryQueue.cpp VideoReferenceClock.cpp - VideoThumbLoader.cpp) + VideoThumbLoader.cpp + ViewModeSettings.cpp) set(HEADERS Bookmark.h ContextMenus.h diff --git a/xbmc/video/Makefile b/xbmc/video/Makefile index be03ee1804..c2b31c648a 100644 --- a/xbmc/video/Makefile +++ b/xbmc/video/Makefile @@ -11,6 +11,7 @@ SRCS=Bookmark.cpp \ VideoLibraryQueue.cpp \ VideoReferenceClock.cpp \ VideoThumbLoader.cpp \ + ViewModeSettings.cpp \ LIB=video.a diff --git a/xbmc/video/ViewModeSettings.cpp b/xbmc/video/ViewModeSettings.cpp new file mode 100644 index 0000000000..bb885df7bc --- /dev/null +++ b/xbmc/video/ViewModeSettings.cpp @@ -0,0 +1,111 @@ +/* + * 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/>. + * + */ + +#include "ViewModeSettings.h" + +#include "cores/IPlayer.h" +#include "guilib/LocalizeStrings.h" +#include "settings/VideoSettings.h" + +struct ViewModeProperties +{ + int stringIndex; + int viewMode; + bool hideFromQuickCycle; + bool hideFromList; +}; + +#define HIDE_ITEM true + +/** The list of all the view modes along with their properties + */ +static const ViewModeProperties viewModes[] = +{ + { 630, ViewModeNormal }, + { 631, ViewModeZoom }, + { 39008, ViewModeZoom120Width }, + { 39009, ViewModeZoom110Width }, + { 632, ViewModeStretch4x3 }, + { 633, ViewModeWideZoom }, + { 634, ViewModeStretch16x9 }, + { 644, ViewModeStretch16x9Nonlin, HIDE_ITEM, HIDE_ITEM }, + { 635, ViewModeOriginal }, + { 636, ViewModeCustom, HIDE_ITEM, HIDE_ITEM } +}; + +#define NUMBER_OF_VIEW_MODES (sizeof(viewModes) / sizeof(viewModes[0])) + +/** Gets the index of a view mode + * + * @param viewMode The view mode + * @return The index of the view mode in the viewModes array + */ +static int GetViewModeIndex(int viewMode) +{ + size_t i; + + // Find the current view mode + for (i = 0; i < NUMBER_OF_VIEW_MODES; i++) + { + if (viewModes[i].viewMode == viewMode) + return i; + } + + return 0; // An invalid view mode will always return the first view mode +} + +/** Gets the next view mode for quick cycling through the modes + * + * @param viewMode The current view mode + * @return The next view mode + */ +int CViewModeSettings::GetNextQuickCycleViewMode(int viewMode) +{ + // Find the next quick cycle view mode + for (size_t i = GetViewModeIndex(viewMode) + 1; i < NUMBER_OF_VIEW_MODES; i++) + { + if (!viewModes[i].hideFromQuickCycle) + return viewModes[i].viewMode; + } + + return ViewModeNormal; +} + +/** Gets the string index for the view mode + * + * @param viewMode The current view mode + * @return The string index + */ +int CViewModeSettings::GetViewModeStringIndex(int viewMode) +{ + return viewModes[GetViewModeIndex(viewMode)].stringIndex; +} + +/** Fills the list with all visible view modes + */ +void CViewModeSettings::ViewModesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t, void *data) +{ + // Add all appropriate view modes to the list control + for (const auto &item : viewModes) + { + if (!item.hideFromList) + list.push_back(make_pair(g_localizeStrings.Get(item.stringIndex), item.viewMode)); + } +} diff --git a/xbmc/video/ViewModeSettings.h b/xbmc/video/ViewModeSettings.h new file mode 100644 index 0000000000..a5c182e830 --- /dev/null +++ b/xbmc/video/ViewModeSettings.h @@ -0,0 +1,55 @@ + +#pragma once + +/* + * 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/>. + * + */ + +#include <string> +#include <utility> +#include <vector> + +#include "settings/lib/Setting.h" + +class CViewModeSettings +{ +private: + CViewModeSettings(); + ~CViewModeSettings() {}; + +public: + /** Gets the next view mode for quick cycling through the modes + * + * @param viewMode The current view mode + * @return The next view mode + */ + static int GetNextQuickCycleViewMode(int viewMode); + + /** Gets the string index for the view mode + * + * @param viewMode The current view mode + * @return The string index + */ + static int GetViewModeStringIndex(int viewMode); + + /** Fills the list with all visible view modes + */ + static void ViewModesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t, void *data); + +}; diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp index 480994d976..c9ffc14b33 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp @@ -38,6 +38,7 @@ #include "Application.h" #include "utils/LangCodeExpander.h" #include "utils/StringUtils.h" +#include "video/ViewModeSettings.h" #define SETTING_VIDEO_VIEW_MODE "video.viewmode" #define SETTING_VIDEO_ZOOM "video.zoom" @@ -332,10 +333,7 @@ void CGUIDialogVideoSettings::InitializeSettings() if (g_application.m_pPlayer->Supports(RENDERFEATURE_STRETCH) || g_application.m_pPlayer->Supports(RENDERFEATURE_PIXEL_RATIO)) { - entries.clear(); - for (int i = 0; i < 7; ++i) - entries.push_back(std::make_pair(630 + i, i)); - AddSpinner(groupVideo, SETTING_VIDEO_VIEW_MODE, 629, 0, videoSettings.m_ViewMode, entries); + AddList(groupVideo, SETTING_VIDEO_VIEW_MODE, 629, 0, videoSettings.m_ViewMode, CViewModeSettings::ViewModesFiller, 629); } if (g_application.m_pPlayer->Supports(RENDERFEATURE_ZOOM)) AddSlider(groupVideo, SETTING_VIDEO_ZOOM, 216, 0, videoSettings.m_CustomZoomAmount, "%2.2f", 0.5f, 0.01f, 2.0f, 216, usePopup); @@ -426,4 +424,3 @@ void CGUIDialogVideoSettings::VideoStreamsOptionFiller(const CSetting *setting, current = -1; } } - diff --git a/xbmc/video/windows/GUIWindowFullScreen.cpp b/xbmc/video/windows/GUIWindowFullScreen.cpp index ef17efdaef..7263752ea8 100644 --- a/xbmc/video/windows/GUIWindowFullScreen.cpp +++ b/xbmc/video/windows/GUIWindowFullScreen.cpp @@ -43,6 +43,7 @@ #include "windowing/WindowingFactory.h" #include "cores/IPlayer.h" #include "guiinfo/GUIInfoLabels.h" +#include "video/ViewModeSettings.h" #include <stdio.h> #include <algorithm> @@ -218,7 +219,7 @@ bool CGUIWindowFullScreen::OnAction(const CAction &action) if (m_bShowViewModeInfo) { #ifdef HAS_VIDEO_PLAYBACK - g_application.m_pPlayer->SetRenderViewMode(++CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode); + g_application.m_pPlayer->SetRenderViewMode(CViewModeSettings::GetNextQuickCycleViewMode(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode)); #endif } m_bShowViewModeInfo = true; @@ -383,7 +384,7 @@ void CGUIWindowFullScreen::FrameMove() // get the "View Mode" string std::string strTitle = g_localizeStrings.Get(629); const auto& settings = CMediaSettings::GetInstance().GetCurrentVideoSettings(); - int sId = settings.m_ViewMode == ViewModeStretch16x9Nonlin ? 644 : 630 + settings.m_ViewMode; + int sId = CViewModeSettings::GetViewModeStringIndex(settings.m_ViewMode); std::string strMode = g_localizeStrings.Get(sId); std::string strInfo = StringUtils::Format("%s : %s", strTitle.c_str(), strMode.c_str()); CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), LABEL_ROW1); |