diff options
35 files changed, 246 insertions, 103 deletions
diff --git a/addons/skin.estouchy/xml/DialogAddonSettings.xml b/addons/skin.estouchy/xml/DialogAddonSettings.xml index 693c7110d7..30dc08a913 100644 --- a/addons/skin.estouchy/xml/DialogAddonSettings.xml +++ b/addons/skin.estouchy/xml/DialogAddonSettings.xml @@ -144,6 +144,7 @@ <description>Default Slider</description> <height>70</height> <font>font25</font> + <textwidth>550</textwidth> </control> <control type="edit" id="12"> <height>70</height> diff --git a/addons/skin.estouchy/xml/DialogSettings.xml b/addons/skin.estouchy/xml/DialogSettings.xml index e7f8e12479..c6886a9a50 100644 --- a/addons/skin.estouchy/xml/DialogSettings.xml +++ b/addons/skin.estouchy/xml/DialogSettings.xml @@ -95,6 +95,7 @@ <control type="sliderex" id="13"> <height>70</height> <font>font25</font> + <textwidth>300</textwidth> </control> <control type="label" id="14"> <posx>0</posx> diff --git a/addons/skin.estuary/xml/Custom_1103_VolumeSlider.xml b/addons/skin.estuary/xml/Custom_1103_VolumeSlider.xml index 04c55bd42c..9805c91c05 100644 --- a/addons/skin.estuary/xml/Custom_1103_VolumeSlider.xml +++ b/addons/skin.estuary/xml/Custom_1103_VolumeSlider.xml @@ -44,27 +44,33 @@ <height>40</height> <texturesliderbar></texturesliderbar> <textureslidernib></textureslidernib> - <textureslidernibfocus colordiffuse="button_focus">colors/white.png</textureslidernibfocus> + <textureslidernibfocus></textureslidernibfocus> <info>Player.Volume</info> <action>Volume</action> </control> - <control type="image"> + <control type="button"> <left>0</left> <top>65</top> <width>28</width> <height>28</height> - <texture flipx="true" colordiffuse="button_focus">overlays/arrowright.png</texture> + <texturefocus flipx="true" colordiffuse="button_focus">overlays/arrowright.png</texturefocus> + <texturenofocus flipx="true" colordiffuse="button_focus">overlays/arrowright.png</texturenofocus> <animation effect="zoom" start="0,100" end="100,100" delay="500" center="auto" time="200">WindowOpen</animation> <animation effect="zoom" start="100,100" end="0,100" center="auto" time="200">WindowClose</animation> + <hitrect x="-20" y="20" w="60" h="112" /> + <onclick>Action(VolumeDown)</onclick> </control> - <control type="image"> + <control type="button"> <left>455</left> <top>65</top> <width>28</width> <height>28</height> - <texture colordiffuse="button_focus">overlays/arrowright.png</texture> + <texturefocus colordiffuse="button_focus">overlays/arrowright.png</texturefocus> + <texturenofocus colordiffuse="button_focus">overlays/arrowright.png</texturenofocus> <animation effect="zoom" start="0,100" end="100,100" delay="500" center="auto" time="200">WindowOpen</animation> <animation effect="zoom" start="100,100" end="0,100" center="auto" time="200">WindowClose</animation> + <hitrect x="440" y="20" w="60" h="112" /> + <onclick>Action(VolumeUp)</onclick> </control> </control> </controls> diff --git a/addons/skin.estuary/xml/DialogAddonSettings.xml b/addons/skin.estuary/xml/DialogAddonSettings.xml index 7d717e6ae4..82dfa0a467 100644 --- a/addons/skin.estuary/xml/DialogAddonSettings.xml +++ b/addons/skin.estuary/xml/DialogAddonSettings.xml @@ -78,6 +78,7 @@ <control type="sliderex" id="13"> <description>Default Slider</description> <include>DefaultSettingButton</include> + <textwidth>700</textwidth> </control> <control type="label" id="14"> <description>Default Label</description> diff --git a/addons/skin.estuary/xml/DialogSettings.xml b/addons/skin.estuary/xml/DialogSettings.xml index 06768db57d..33648603cb 100644 --- a/addons/skin.estuary/xml/DialogSettings.xml +++ b/addons/skin.estuary/xml/DialogSettings.xml @@ -56,6 +56,7 @@ <control type="sliderex" id="13"> <description>Default Slider</description> <include>DefaultSettingButton</include> + <textwidth>800</textwidth> </control> <control type="label" id="14"> <description>Default Label</description> diff --git a/cmake/installdata/windows/addons.txt b/cmake/installdata/windows/addons.txt index a3bdd4493b..66b583a23f 100644 --- a/cmake/installdata/windows/addons.txt +++ b/cmake/installdata/windows/addons.txt @@ -1,3 +1,2 @@ -addons/repository.pvr-win32.xbmc.org/* project/BuildDependencies/${ARCH}/addons/script.module.pil KEEP_DIR_STRUCTURE addons project/BuildDependencies/${ARCH}/addons/script.module.pycryptodome KEEP_DIR_STRUCTURE addons diff --git a/cmake/installdata/windowsstore/addons.txt b/cmake/installdata/windowsstore/addons.txt index 4b8678b682..3b4d9a949b 100644 --- a/cmake/installdata/windowsstore/addons.txt +++ b/cmake/installdata/windowsstore/addons.txt @@ -1,3 +1,2 @@ -addons/repository.pvr-win32.xbmc.org/* project/BuildDependencies/win10-${ARCH}/addons/* -system/addon-manifest-uwp.xml
\ No newline at end of file +system/addon-manifest-uwp.xml diff --git a/cmake/scripts/common/HandleDepends.cmake b/cmake/scripts/common/HandleDepends.cmake index 47f7d9b768..40e382b94c 100644 --- a/cmake/scripts/common/HandleDepends.cmake +++ b/cmake/scripts/common/HandleDepends.cmake @@ -88,16 +88,12 @@ function(add_addon_depends addon searchpath) message(${BUILD_ARGS}) endif() - # prepare patchfile. ensure we have a clean file after reconfiguring - set(PATCH_FILE ${BUILD_DIR}/${id}/tmp/patch.cmake) - file(REMOVE ${PATCH_FILE}) + set(PATCH_COMMAND) # if there's a CMakeLists.txt use it to prepare the build if(EXISTS ${dir}/CMakeLists.txt) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/CMakeLists.txt) - file(APPEND ${PATCH_FILE} - "file(COPY ${dir}/CMakeLists.txt - DESTINATION ${BUILD_DIR}/${id}/src/${id})\n") + list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_if_different ${dir}/CMakeLists.txt ${BUILD_DIR}/${id}/src/${id}) endif() # check if we have patches to apply @@ -124,14 +120,13 @@ function(add_addon_depends addon searchpath) file(READ ${patch} patch_content_hex HEX) # Force handle LF-only line endings if(NOT patch_content_hex MATCHES "0d0a") - set(PATCH_PROGRAM "\"${PATCH_PROGRAM}\" --binary") + list(APPEND PATCH_PROGRAM --binary) endif() endif() endif() set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${patch}) - file(APPEND ${PATCH_FILE} - "execute_process(COMMAND ${PATCH_PROGRAM} -p1 -i \"${patch}\")\n") + list(APPEND PATCH_COMMAND COMMAND ${PATCH_PROGRAM} -p1 -i ${patch}) endforeach() @@ -168,18 +163,11 @@ function(add_addon_depends addon searchpath) if(CROSS_AUTOCONF AND AUTOCONF_FILES) foreach(afile ${AUTOCONF_FILES}) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${afile}) - file(APPEND ${PATCH_FILE} - "message(STATUS \"AUTOCONF: copying ${afile} to ${BUILD_DIR}/${id}/src/${id}\")\n - file(COPY ${afile} DESTINATION ${BUILD_DIR}/${id}/src/${id})\n") + list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E echo "AUTOCONF: copying ${afile} to ${BUILD_DIR}/${id}/src/${id}") + list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_if_different ${afile} ${BUILD_DIR}/${id}/src/${id}) endforeach() endif() - # if the patch file exists we need to set the PATCH_COMMAND - set(PATCH_COMMAND "") - if(EXISTS ${PATCH_FILE}) - set(PATCH_COMMAND ${CMAKE_COMMAND} -P ${PATCH_FILE}) - endif() - # prepare the setup of the call to externalproject_add() set(EXTERNALPROJECT_SETUP PREFIX ${BUILD_DIR}/${id} CMAKE_ARGS ${extraflags} ${BUILD_ARGS} diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml index c4b50cd482..41fd40eea8 100644 --- a/system/keymaps/joystick.xml +++ b/system/keymaps/joystick.xml @@ -91,8 +91,8 @@ <FullscreenVideo> <joystick profile="game.controller.default"> <a>Pause</a> - <b>Fullscreen</b> - <b holdtime="500">Stop</b> + <b>Stop</b> + <b holdtime="500">FullScreen</b> <x>OSD</x> <y>FullScreen</y> <start>Info</start> @@ -169,6 +169,9 @@ </FullscreenGame> <FullscreenLiveTV> <joystick profile="game.controller.default"> + <a>Pause</a> + <b>Stop</b> + <b holdtime="500">FullScreen</b> <x>OSD</x> <back>OSD</back> <guide>OSD</guide> @@ -186,6 +189,9 @@ </TVGuide> <FullscreenRadio> <joystick profile="game.controller.default"> + <a>Pause</a> + <b>Stop</b> + <b holdtime="500">FullScreen</b> <x>OSD</x> <back>OSD</back> <guide>OSD</guide> diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index dd092f512d..f184899b37 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -1454,13 +1454,13 @@ void CFileItem::FillInMimeType(bool lookup /*= true*/) if (!lookup) return; - CCurlFile::GetMimeType(GetURL(), m_mimetype); + CCurlFile::GetMimeType(GetDynURL(), m_mimetype); // try to get mime-type again but with an NSPlayer User-Agent // in order for server to provide correct mime-type. Allows us // to properly detect an MMS stream if (StringUtils::StartsWithNoCase(m_mimetype, "video/x-ms-")) - CCurlFile::GetMimeType(GetURL(), m_mimetype, "NSPlayer/11.00.6001.7000"); + CCurlFile::GetMimeType(GetDynURL(), m_mimetype, "NSPlayer/11.00.6001.7000"); // make sure there are no options set in mime-type // mime-type can look like "video/x-ms-asf ; charset=utf8" diff --git a/xbmc/addons/PVRClient.cpp b/xbmc/addons/PVRClient.cpp index c2752e8e52..46fcf66687 100644 --- a/xbmc/addons/PVRClient.cpp +++ b/xbmc/addons/PVRClient.cpp @@ -188,6 +188,7 @@ void CPVRClient::Destroy(void) void CPVRClient::Stop() { m_bBlockAddonCalls = true; + m_bPriorityFetched = false; } void CPVRClient::Continue() diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp index 9614288c37..1ee372c1fb 100644 --- a/xbmc/addons/Skin.cpp +++ b/xbmc/addons/Skin.cpp @@ -392,6 +392,9 @@ const INFO::CSkinVariableString* CSkinInfo::CreateSkinVariable(const std::string void CSkinInfo::OnPreInstall() { + bool skinLoaded = g_SkinInfo != nullptr; + if (IsInUse() && skinLoaded) + CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, "UnloadSkin"); } void CSkinInfo::OnPostInstall(bool update, bool modal) diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h index 42ce2e73fe..8e45693a16 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h @@ -43,6 +43,20 @@ #define ATTRIBUTE_HIDDEN #endif +#ifdef _MSC_VER + #define ATTRIBUTE_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) +#elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define ATTRIBUTE_FORCEINLINE inline __attribute__((__always_inline__)) + #else + #define ATTRIBUTE_FORCEINLINE inline + #endif +#else + #define ATTRIBUTE_FORCEINLINE inline +#endif + #include "versions.h" namespace kodi { namespace addon { class CAddonBase; }} diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h index 1c706514ef..06d75e02c5 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h @@ -30,7 +30,7 @@ * overview. */ -#define ADDON_GLOBAL_VERSION_MAIN "1.0.13" +#define ADDON_GLOBAL_VERSION_MAIN "1.0.14" #define ADDON_GLOBAL_VERSION_MAIN_MIN "1.0.12" #define ADDON_GLOBAL_VERSION_MAIN_XML_ID "kodi.binary.global.main" #define ADDON_GLOBAL_VERSION_MAIN_DEPENDS "AddonBase.h" \ diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp index 4f057e6fac..5ad2bcbf33 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -670,7 +670,14 @@ bool CVideoPlayerVideo::ProcessDecoderOutput(double &frametime, double &pts) // use forced aspect if any if (m_fForcedAspectRatio != 0.0f) + { m_picture.iDisplayWidth = (int) (m_picture.iDisplayHeight * m_fForcedAspectRatio); + if (m_picture.iDisplayWidth > m_picture.iWidth) + { + m_picture.iDisplayWidth = m_picture.iWidth; + m_picture.iDisplayHeight = (int) (m_picture.iDisplayWidth / m_fForcedAspectRatio); + } + } // set stereo mode if not set by decoder if (m_picture.stereoMode.empty()) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp index ed15f8976e..ec4df26904 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp @@ -46,6 +46,9 @@ CLinuxRendererGLES::~CLinuxRendererGLES() UnInit(); ReleaseShaders(); + + free(m_planeBuffer); + m_planeBuffer = nullptr; } CBaseRenderer* CLinuxRendererGLES::Create(CVideoBuffer *buffer) @@ -260,18 +263,45 @@ void CLinuxRendererGLES::LoadPlane(CYuvPlane& plane, int type, glBindTexture(m_textureTarget, plane.id); // OpenGL ES does not support strided texture input. + GLint pixelStore = -1; + unsigned int pixelStoreKey = -1; + if (stride != static_cast<int>(width * bps)) { - unsigned char* src = static_cast<unsigned char*>(data); - for (unsigned int y = 0; y < height; ++y, src += stride) +#if HAS_GLES >= 3 + unsigned int verMajor, verMinor; + m_renderSystem->GetRenderVersion(verMajor, verMinor); + + if (verMajor >= 3) { - glTexSubImage2D(m_textureTarget, 0, 0, y, width, 1, type, GL_UNSIGNED_BYTE, src); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &pixelStore); + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + pixelStoreKey = GL_UNPACK_ROW_LENGTH; + } + else +#elif defined (GL_UNPACK_ROW_LENGTH_EXT) + if (m_renderSystem->IsExtSupported("GL_EXT_unpack_subimage")) + { + glGetIntegerv(GL_UNPACK_ROW_LENGTH_EXT, &pixelStore); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); + pixelStoreKey = GL_UNPACK_ROW_LENGTH_EXT; + } + else +#endif + { + unsigned char *src(static_cast<unsigned char*>(data)), + *dst(m_planeBuffer); + + for (unsigned int y = 0; y < height; ++y, src += stride, dst += width * bpp) + memcpy(dst, src, width * bpp); + + pixelData = m_planeBuffer; } } - else - { - glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, pixelData); - } + glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, pixelData); + + if (pixelStore >= 0) + glPixelStorei(pixelStoreKey, pixelStore); // check if we need to load any border pixels if (height < plane.texheight) @@ -1262,6 +1292,8 @@ bool CLinuxRendererGLES::CreateYV12Texture(int index) im.planesize[1] = im.stride[1] * (im.height >> im.cshift_y); im.planesize[2] = im.stride[2] * (im.height >> im.cshift_y); + m_planeBuffer = static_cast<unsigned char*>(realloc(m_planeBuffer, m_sourceHeight * m_sourceWidth * im.bpp)); + for (int i = 0; i < 3; i++) { im.plane[i] = new uint8_t[im.planesize[i]]; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h index 56c401aca1..f0a310ff93 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h @@ -201,6 +201,7 @@ protected: bool m_fullRange; AVColorPrimaries m_srcPrimaries; bool m_toneMap = false; + unsigned char* m_planeBuffer = nullptr; // clear colour for "black" bars float m_clearColour{0.0f}; diff --git a/xbmc/filesystem/File.cpp b/xbmc/filesystem/File.cpp index 968b02b978..5402816175 100644 --- a/xbmc/filesystem/File.cpp +++ b/xbmc/filesystem/File.cpp @@ -74,7 +74,7 @@ bool CFile::Copy(const CURL& url2, const CURL& dest, XFILE::IFileCallback* pCall // special case for zips - ignore caching CURL url(url2); - if (URIUtils::IsInZIP(url.Get()) || URIUtils::IsInAPK(url.Get())) + if (StringUtils::StartsWith(url.Get(), "zip://") || URIUtils::IsInAPK(url.Get())) url.SetOptions("?cache=no"); if (file.Open(url.Get(), READ_TRUNCATED | READ_CHUNKED)) { diff --git a/xbmc/guilib/GUIBaseContainer.cpp b/xbmc/guilib/GUIBaseContainer.cpp index 7d1985bade..1bcea2700f 100644 --- a/xbmc/guilib/GUIBaseContainer.cpp +++ b/xbmc/guilib/GUIBaseContainer.cpp @@ -58,6 +58,10 @@ CGUIBaseContainer::CGUIBaseContainer(const CGUIBaseContainer &) = default; CGUIBaseContainer::~CGUIBaseContainer(void) { + // release the container from items + for (auto item : m_items) + item->FreeMemory(); + delete m_listProvider; } diff --git a/xbmc/guilib/GUISliderControl.cpp b/xbmc/guilib/GUISliderControl.cpp index 5c4198fd33..fec4e84712 100644 --- a/xbmc/guilib/GUISliderControl.cpp +++ b/xbmc/guilib/GUISliderControl.cpp @@ -69,26 +69,28 @@ void CGUISliderControl::Process(unsigned int currentTime, CDirtyRegionList &dirt SetIntValue(val); } - dirty |= m_guiBackground.SetHeight(m_height); dirty |= m_guiBackground.SetWidth(m_width); dirty |= m_guiBackground.Process(currentTime); CGUITexture &nibLower = (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorLower) ? m_guiSelectorLowerFocus : m_guiSelectorLower; - float fScale; - if (m_orientation == HORIZONTAL) - fScale = m_height == 0 ? 1.0f : m_height / m_guiBackground.GetTextureHeight(); - else - fScale = m_width == 0 ? 1.0f : m_width / nibLower.GetTextureWidth(); + float fScale = 1.0f; + + if (m_orientation == HORIZONTAL && m_guiBackground.GetTextureHeight() != 0) + fScale = m_height / m_guiBackground.GetTextureHeight(); + else if (m_width != 0 && nibLower.GetTextureWidth() != 0) + fScale = m_width / nibLower.GetTextureWidth(); dirty |= ProcessSelector(nibLower, currentTime, fScale, RangeSelectorLower); if (m_rangeSelection) { CGUITexture &nibUpper = (IsActive() && m_bHasFocus && !IsDisabled() && m_currentSelector == RangeSelectorUpper) ? m_guiSelectorUpperFocus : m_guiSelectorUpper; - if (m_orientation == HORIZONTAL) - fScale = m_height == 0 ? 1.0f : m_height / m_guiBackground.GetTextureHeight(); - else - fScale = m_width == 0 ? 1.0f : m_width / nibUpper.GetTextureWidth(); + + if (m_orientation == HORIZONTAL && m_guiBackground.GetTextureHeight() != 0) + fScale = m_height / m_guiBackground.GetTextureHeight(); + else if (m_width != 0 && nibUpper.GetTextureWidth() != 0) + fScale = m_width / nibUpper.GetTextureWidth(); + dirty |= ProcessSelector(nibUpper, currentTime, fScale, RangeSelectorUpper); } diff --git a/xbmc/guilib/GUISliderControl.dox b/xbmc/guilib/GUISliderControl.dox index 04651dc179..10bd2ba514 100644 --- a/xbmc/guilib/GUISliderControl.dox +++ b/xbmc/guilib/GUISliderControl.dox @@ -54,8 +54,11 @@ important, as xml tags are case-sensitive. | controloffsety | Amount to offset the slider background texture from the top edge of the control. | info | Specifies the information that the slider controls. [See here for more information](http://kodi.wiki/view/InfoLabels). | orientation | Specifies whether this scrollbar is horizontal or vertical. Defaults to vertical. -| action | Can be <b>'volume'</b> to adjust the volume or 'seek' to change the seek position. +| action | Can be <b>`volume`</b> to adjust the volume, <b>`seek`</b> to change the seek position, <b>`pvr.seek`</b> for timeshifting in PVR. +\section Slider_Control_revhistory Revision History + +@skinning_v18 <b>[Slider Control]</b> Added <b>`pvr.seek`</b> as possible <b>action</b> tag value (timeshifting in PVR). -------------------------------------------------------------------------------- \section Slider_Control_sect3 See also diff --git a/xbmc/guilib/TextureBundle.cpp b/xbmc/guilib/TextureBundle.cpp index 9f28b601d0..3f41a09818 100644 --- a/xbmc/guilib/TextureBundle.cpp +++ b/xbmc/guilib/TextureBundle.cpp @@ -66,6 +66,11 @@ int CTextureBundle::LoadAnim(const std::string& Filename, CBaseTexture*** ppText return 0; } +void CTextureBundle::Close() +{ + m_tbXBT.CloseBundle(); +} + void CTextureBundle::SetThemeBundle(bool themeBundle) { m_tbXBT.SetThemeBundle(themeBundle); diff --git a/xbmc/guilib/TextureBundle.h b/xbmc/guilib/TextureBundle.h index 557472741d..4d3ef95de4 100644 --- a/xbmc/guilib/TextureBundle.h +++ b/xbmc/guilib/TextureBundle.h @@ -27,7 +27,7 @@ public: bool LoadTexture(const std::string& Filename, CBaseTexture** ppTexture, int &width, int &height); int LoadAnim(const std::string& Filename, CBaseTexture*** ppTextures, int &width, int &height, int& nLoops, int** ppDelays); - + void Close(); private: CTextureBundleXBT m_tbXBT; diff --git a/xbmc/guilib/TextureBundleXBT.cpp b/xbmc/guilib/TextureBundleXBT.cpp index 9a5cd68a86..1fa2d6659c 100644 --- a/xbmc/guilib/TextureBundleXBT.cpp +++ b/xbmc/guilib/TextureBundleXBT.cpp @@ -46,6 +46,11 @@ CTextureBundleXBT::CTextureBundleXBT(bool themeBundle) CTextureBundleXBT::~CTextureBundleXBT(void) { + CloseBundle(); +} + +void CTextureBundleXBT::CloseBundle() +{ if (m_XBTFReader != nullptr && m_XBTFReader->IsOpen()) { XFILE::CXbtManager::GetInstance().Release(CURL(m_path)); diff --git a/xbmc/guilib/TextureBundleXBT.h b/xbmc/guilib/TextureBundleXBT.h index 669f634d47..191499833e 100644 --- a/xbmc/guilib/TextureBundleXBT.h +++ b/xbmc/guilib/TextureBundleXBT.h @@ -37,6 +37,8 @@ public: int &width, int &height, int& nLoops, int** ppDelays); static uint8_t* UnpackFrame(const CXBTFReader& reader, const CXBTFFrame& frame); + + void CloseBundle(); private: bool OpenBundle(); diff --git a/xbmc/guilib/TextureManager.cpp b/xbmc/guilib/TextureManager.cpp index 4ec1336766..59a4ffb896 100644 --- a/xbmc/guilib/TextureManager.cpp +++ b/xbmc/guilib/TextureManager.cpp @@ -533,7 +533,8 @@ void CGUITextureManager::Cleanup() delete pMap; i = m_vecTextures.erase(i); } - + m_TexBundle[0].Close(); + m_TexBundle[1].Close(); m_TexBundle[0] = CTextureBundle(true); m_TexBundle[1] = CTextureBundle(); FreeUnusedTextures(); diff --git a/xbmc/interfaces/json-rpc/schema/version.txt b/xbmc/interfaces/json-rpc/schema/version.txt index e479a93f04..acd39a4eec 100644 --- a/xbmc/interfaces/json-rpc/schema/version.txt +++ b/xbmc/interfaces/json-rpc/schema/version.txt @@ -1 +1 @@ -JSONRPC_VERSION 10.1.0 +JSONRPC_VERSION 10.1.1 diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp index 7f55822e90..59c8319b37 100644 --- a/xbmc/music/MusicDatabase.cpp +++ b/xbmc/music/MusicDatabase.cpp @@ -4166,8 +4166,6 @@ bool CMusicDatabase::GetArtistsNav(const std::string& strBaseDir, CFileItemList& if (NULL == m_pDS.get()) return false; try { - unsigned int time = XbmcThreads::SystemClockMillis(); - CMusicDbUrl musicUrl; if (!musicUrl.FromString(strBaseDir)) return false; @@ -4185,7 +4183,6 @@ bool CMusicDatabase::GetArtistsNav(const std::string& strBaseDir, CFileItemList& musicUrl.AddOption("albumartistsonly", albumArtistsOnly); bool result = GetArtistsByWhere(musicUrl.ToString(), filter, items, sortDescription, countOnly); - CLog::Log(LOGDEBUG,"Time to retrieve artists from dataset = %i", XbmcThreads::SystemClockMillis() - time); return result; } @@ -4204,6 +4201,8 @@ bool CMusicDatabase::GetArtistsByWhere(const std::string& strBaseDir, const Filt try { + unsigned int querytime = 0; + unsigned int time = XbmcThreads::SystemClockMillis(); int total = -1; std::string strSQL = "SELECT %s FROM artistview "; @@ -4245,12 +4244,15 @@ bool CMusicDatabase::GetArtistsByWhere(const std::string& strBaseDir, const Filt if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra)) return false; - // Apply the limiting directly here if there's no special sorting but limiting - if (extFilter.limit.empty() && - sortDescription.sortBy == SortByNone && - (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0)) + // Apply limits and sort order directly in SQL when random sort or none + bool limitedInSQL = extFilter.limit.empty() && + (sortDescription.sortBy == SortByNone || sortDescription.sortBy == SortByRandom) && + (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0); + if (limitedInSQL) { total = (int)strtol(GetSingleValue(PrepareSQL(strSQL, "COUNT(1)") + strSQLExtra, m_pDS).c_str(), NULL, 10); + if (sortDescription.sortBy == SortByRandom) + strSQLExtra += PrepareSQL(" ORDER BY RANDOM()"); strSQLExtra += DatabaseUtils::BuildLimitClause(sortDescription.limitEnd, sortDescription.limitStart); } @@ -4258,13 +4260,16 @@ bool CMusicDatabase::GetArtistsByWhere(const std::string& strBaseDir, const Filt // run query CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str()); - if (!m_pDS->query(strSQL)) return false; + querytime = XbmcThreads::SystemClockMillis(); + if (!m_pDS->query(strSQL)) + return false; int iRowsFound = m_pDS->num_rows(); if (iRowsFound == 0) { m_pDS->close(); return true; } + querytime = XbmcThreads::SystemClockMillis() - querytime; if (countOnly) { @@ -4283,9 +4288,14 @@ bool CMusicDatabase::GetArtistsByWhere(const std::string& strBaseDir, const Filt DatabaseResults results; results.reserve(iRowsFound); - if (!SortUtils::SortFromDataset(sortDescription, MediaTypeArtist, m_pDS, results)) - return false; + // Random order with limits already applied in SQL, just fetch results from dataset + sorting = sortDescription; + if (limitedInSQL && sortDescription.sortBy == SortByRandom) + sorting.sortBy = SortByNone; + if (!SortUtils::SortFromDataset(sorting, MediaTypeSong, m_pDS, results)) + return false; + // get data from returned rows items.Reserve(results.size()); const dbiplus::query_data &data = m_pDS->get_result_set().records; @@ -4320,6 +4330,8 @@ bool CMusicDatabase::GetArtistsByWhere(const std::string& strBaseDir, const Filt // cleanup m_pDS->close(); + CLog::Log(LOGDEBUG, "{0}: Time to fill list with artists {1}ms query took {2}ms", + __FUNCTION__, XbmcThreads::SystemClockMillis() - time, querytime); return true; } catch (...) @@ -4382,6 +4394,8 @@ bool CMusicDatabase::GetAlbumsByWhere(const std::string &baseDir, const Filter & try { + unsigned int querytime = 0; + unsigned int time = XbmcThreads::SystemClockMillis(); int total = -1; std::string strSQL = "SELECT %s FROM albumview "; @@ -4404,31 +4418,32 @@ bool CMusicDatabase::GetAlbumsByWhere(const std::string &baseDir, const Filter & if (!BuildSQL(strSQLExtra, extFilter, strSQLExtra)) return false; - // Apply the limiting directly here if there's no special sorting but limiting - if (extFilter.limit.empty() && - sortDescription.sortBy == SortByNone && - (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0)) + // Apply limits and sort order directly in SQL when random sort or none + bool limitedInSQL = extFilter.limit.empty() && + (sortDescription.sortBy == SortByNone || sortDescription.sortBy == SortByRandom) && + (sortDescription.limitStart > 0 || sortDescription.limitEnd > 0); + if (limitedInSQL) { total = (int)strtol(GetSingleValue(PrepareSQL(strSQL, "COUNT(1)") + strSQLExtra, m_pDS).c_str(), NULL, 10); + if (sortDescription.sortBy == SortByRandom) + strSQLExtra += PrepareSQL(" ORDER BY RANDOM()"); strSQLExtra += DatabaseUtils::BuildLimitClause(sortDescription.limitEnd, sortDescription.limitStart); } strSQL = PrepareSQL(strSQL, !filter.fields.empty() && filter.fields.compare("*") != 0 ? filter.fields.c_str() : "albumview.*") + strSQLExtra; - CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str()); // run query - unsigned int time = XbmcThreads::SystemClockMillis(); - if (!m_pDS->query(strSQL)) + CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str()); + querytime = XbmcThreads::SystemClockMillis(); + if (!m_pDS->query(strSQL)) return false; - CLog::Log(LOGDEBUG, "%s - query took %i ms", - __FUNCTION__, XbmcThreads::SystemClockMillis() - time); time = XbmcThreads::SystemClockMillis(); - int iRowsFound = m_pDS->num_rows(); - if (iRowsFound <= 0) + if (iRowsFound == 0) { m_pDS->close(); return true; } + querytime = XbmcThreads::SystemClockMillis() - querytime; // store the total value of items as a property if (total < iRowsFound) @@ -4447,7 +4462,12 @@ bool CMusicDatabase::GetAlbumsByWhere(const std::string &baseDir, const Filter & DatabaseResults results; results.reserve(iRowsFound); - if (!SortUtils::SortFromDataset(sortDescription, MediaTypeAlbum, m_pDS, results)) + + // Random order with limits already applied in SQL, just fetch results from dataset + sorting = sortDescription; + if (limitedInSQL && sortDescription.sortBy == SortByRandom) + sorting.sortBy = SortByNone; + if (!SortUtils::SortFromDataset(sorting, MediaTypeSong, m_pDS, results)) return false; // get data from returned rows @@ -4477,6 +4497,8 @@ bool CMusicDatabase::GetAlbumsByWhere(const std::string &baseDir, const Filter & // cleanup m_pDS->close(); + CLog::Log(LOGDEBUG, "{0}: Time to fill list with albums {1}ms query took {2}ms", + __FUNCTION__, XbmcThreads::SystemClockMillis() - time, querytime); return true; } catch (...) @@ -8783,7 +8805,7 @@ bool CMusicDatabase::GetGenresJSON(CFileItemList& items, bool bSources) extFilter.AppendJoin("JOIN song_genre ON song_genre.idGenre = genre.idGenre"); extFilter.AppendJoin("JOIN song ON song.idSong = song_genre.idSong"); extFilter.AppendJoin("JOIN album ON album.idAlbum = song.idAlbum"); - extFilter.AppendJoin("JOIN album_source on album_source.idAlbum = album.idAlbum"); + extFilter.AppendJoin("LEFT JOIN album_source on album_source.idAlbum = album.idAlbum"); extFilter.AppendOrder("genre.strGenre"); extFilter.AppendOrder("album_source.idSource"); } @@ -8795,7 +8817,6 @@ bool CMusicDatabase::GetGenresJSON(CFileItemList& items, bool bSources) strSQL = PrepareSQL(strSQL.c_str(), extFilter.fields.c_str()) + strSQLExtra; - // run query CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str()); @@ -8819,7 +8840,7 @@ bool CMusicDatabase::GetGenresJSON(CFileItemList& items, bool bSources) { if (idGenre != m_pDS->fv("genre.idGenre").get_asInt()) { // New genre - if (idGenre > 0 && !genreSources.empty()) + if (idGenre > 0 && bSources) { //Store sources for previous genre in item list items[items.Size() - 1].get()->SetProperty("sourceid", genreSources); @@ -8837,14 +8858,17 @@ bool CMusicDatabase::GetGenresJSON(CFileItemList& items, bool bSources) } // Get source data if (bSources) - genreSources.push_back(m_pDS->fv("album_source.idSource").get_asInt()); + { + int sourceid = m_pDS->fv("album_source.idSource").get_asInt(); + if (sourceid > 0) + genreSources.push_back(sourceid); + } m_pDS->next(); } - if (!genreSources.empty()) + if (bSources) { //Store sources for final genre items[items.Size() - 1].get()->SetProperty("sourceid", genreSources); - genreSources.clear(); } // cleanup diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp index 97e7d0fd76..34d7f54ef5 100644 --- a/xbmc/pvr/addons/PVRClients.cpp +++ b/xbmc/pvr/addons/PVRClients.cpp @@ -476,7 +476,11 @@ bool CPVRClients::GetTimers(CPVRTimersContainer *timers, std::vector<int> &faile PVR_ERROR CPVRClients::GetTimerTypes(CPVRTimerTypes& results) const { return ForCreatedClients(__FUNCTION__, [&results](const CPVRClientPtr &client) { - return client->GetTimerTypes(results); + CPVRTimerTypes types; + PVR_ERROR ret = client->GetTimerTypes(types); + if (ret == PVR_ERROR_NO_ERROR) + results.insert(results.end(), types.begin(), types.end()); + return ret; }); } diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp index d312e37f77..4293a18cf5 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.cpp +++ b/xbmc/pvr/channels/PVRChannelGroup.cpp @@ -846,7 +846,9 @@ bool CPVRChannelGroup::Renumber(void) (*it).channelNumber = currentChannelNumber; } - (*it).channel->SetChannelNumber((*it).channelNumber); + //! @todo This is a quick fix for v18. Whole channel number handling should be reworked - code is imo unmaintainable. + if (IsInternalGroup()) + (*it).channel->SetChannelNumber((*it).channelNumber); } SortByChannelNumber(); diff --git a/xbmc/utils/CryptThreading.cpp b/xbmc/utils/CryptThreading.cpp index c0a2c3e02c..e604d6363b 100644 --- a/xbmc/utils/CryptThreading.cpp +++ b/xbmc/utils/CryptThreading.cpp @@ -12,7 +12,10 @@ #include <openssl/crypto.h> +//! @todo Remove support for OpenSSL <1.0 in v19 + #define KODI_OPENSSL_NEEDS_LOCK_CALLBACK (OPENSSL_VERSION_NUMBER < 0x10100000L) +#define KODI_OPENSSL_USE_THREADID (OPENSSL_VERSION_NUMBER >= 0x10000000L) #if KODI_OPENSSL_NEEDS_LOCK_CALLBACK namespace @@ -31,11 +34,19 @@ void lock_callback(int mode, int type, const char* file, int line) getlock(type)->unlock(); } +#if KODI_OPENSSL_USE_THREADID +void thread_id(CRYPTO_THREADID* tid) +{ + // C-style cast required due to vastly differing native ID return types + CRYPTO_THREADID_set_numeric(tid, (unsigned long)CThread::GetCurrentThreadId()); +} +#else unsigned long thread_id() { // C-style cast required due to vastly differing native ID return types return (unsigned long)CThread::GetCurrentThreadId(); } +#endif } #endif @@ -46,7 +57,11 @@ CryptThreadingInitializer::CryptThreadingInitializer() // OpenSSL < 1.1 needs integration code to support multi-threading // This is absolutely required for libcurl if it uses the OpenSSL backend m_locks.resize(CRYPTO_num_locks()); +#if KODI_OPENSSL_USE_THREADID + CRYPTO_THREADID_set_callback(thread_id); +#else CRYPTO_set_id_callback(thread_id); +#endif CRYPTO_set_locking_callback(lock_callback); #endif } @@ -55,7 +70,9 @@ CryptThreadingInitializer::~CryptThreadingInitializer() { #if KODI_OPENSSL_NEEDS_LOCK_CALLBACK CSingleLock l(m_locksLock); +#if !KODI_OPENSSL_USE_THREADID CRYPTO_set_id_callback(nullptr); +#endif CRYPTO_set_locking_callback(nullptr); m_locks.clear(); #endif diff --git a/xbmc/windowing/Resolution.cpp b/xbmc/windowing/Resolution.cpp index 53427f965e..e28708ff06 100644 --- a/xbmc/windowing/Resolution.cpp +++ b/xbmc/windowing/Resolution.cpp @@ -109,8 +109,9 @@ void CResolutionUtils::FindResolutionFromWhitelist(float fps, int width, int hei const RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(i); // allow resolutions that are exact and have the correct refresh rate - if (((height == info.iScreenHeight && width <= info.iScreenWidth) || - (width == info.iScreenWidth && height <= info.iScreenHeight)) && + // allow macroblock alignement / padding errors (e.g. 1080 mod16 == 8) + if (((height == info.iScreenHeight && width <= info.iScreenWidth + 8) || + (width == info.iScreenWidth && height <= info.iScreenHeight + 8)) && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) && MathUtils::FloatEquals(info.fRefreshRate, fps, 0.01f)) { @@ -128,8 +129,9 @@ void CResolutionUtils::FindResolutionFromWhitelist(float fps, int width, int hei const RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(i); // allow resolutions that are exact and have double the refresh rate - if (((height == info.iScreenHeight && width <= info.iScreenWidth) || - (width == info.iScreenWidth && height <= info.iScreenHeight)) && + // allow macroblock alignement / padding errors (e.g. 1080 mod16 == 8) + if (((height == info.iScreenHeight && width <= info.iScreenWidth + 8) || + (width == info.iScreenWidth && height <= info.iScreenHeight + 8)) && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) && MathUtils::FloatEquals(info.fRefreshRate, fps * 2, 0.01f)) { @@ -141,15 +143,15 @@ void CResolutionUtils::FindResolutionFromWhitelist(float fps, int width, int hei CLog::Log(LOGDEBUG, "No double refresh rate whitelisted resolution matched, trying current resolution"); + const RESOLUTION_INFO desktop_info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(CDisplaySettings::GetInstance().GetCurrentResolution()); + for (const auto &mode : indexList) { auto i = CDisplaySettings::GetInstance().GetResFromString(mode.asString()); const RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(i); - const RESOLUTION_INFO desktop_info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(CDisplaySettings::GetInstance().GetCurrentResolution()); - // allow resolutions that are desktop resolution but have the correct refresh rate - if (info.iScreenWidth == desktop_info.iWidth && + if (info.iScreenWidth == desktop_info.iScreenWidth && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (desktop_info.dwFlags & D3DPRESENTFLAG_MODEMASK) && MathUtils::FloatEquals(info.fRefreshRate, fps, 0.01f)) { @@ -166,10 +168,8 @@ void CResolutionUtils::FindResolutionFromWhitelist(float fps, int width, int hei auto i = CDisplaySettings::GetInstance().GetResFromString(mode.asString()); const RESOLUTION_INFO info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(i); - const RESOLUTION_INFO desktop_info = CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo(CDisplaySettings::GetInstance().GetCurrentResolution()); - // allow resolutions that are desktop resolution but have double the refresh rate - if (info.iScreenWidth == desktop_info.iWidth && + if (info.iScreenWidth == desktop_info.iScreenWidth && (info.dwFlags & D3DPRESENTFLAG_MODEMASK) == (desktop_info.dwFlags & D3DPRESENTFLAG_MODEMASK) && MathUtils::FloatEquals(info.fRefreshRate, fps * 2, 0.01f)) { diff --git a/xbmc/windowing/X11/GLContextEGL.cpp b/xbmc/windowing/X11/GLContextEGL.cpp index 2b6b5d35e3..6d02068c76 100644 --- a/xbmc/windowing/X11/GLContextEGL.cpp +++ b/xbmc/windowing/X11/GLContextEGL.cpp @@ -21,6 +21,7 @@ #include "ServiceBroker.h" #include "settings/AdvancedSettings.h" #include "settings/SettingsComponent.h" +#include "threads/SingleLock.h" #define EGL_NO_CONFIG (EGLConfig)0 @@ -420,6 +421,8 @@ void CGLContextEGL::SwapBuffers() uint64_t sbc1, sbc2; struct timespec nowTs; uint64_t now; + uint64_t cont = m_sync.cont; + uint64_t interval = m_sync.interval; eglGetSyncValuesCHROMIUM(m_eglDisplay, m_eglSurface, &ust1, &msc1, &sbc1); @@ -432,7 +435,7 @@ void CGLContextEGL::SwapBuffers() if ((msc1 - m_sync.msc1) > 2) { - m_sync.cont = 0; + cont = 0; } // we want to block in SwapBuffers @@ -442,12 +445,12 @@ void CGLContextEGL::SwapBuffers() { if ((msc1 - m_sync.msc1) == 2) { - m_sync.cont = 0; + cont = 0; } else if ((msc1 - m_sync.msc1) == 1) { - m_sync.interval = (ust1 - m_sync.ust1) / (msc1 - m_sync.msc1); - m_sync.cont++; + interval = (ust1 - m_sync.ust1) / (msc1 - m_sync.msc1); + cont++; } } else if (m_sync.cont == 5 && m_omlSync) @@ -466,7 +469,7 @@ void CGLContextEGL::SwapBuffers() } uint64_t sleeptime = m_sync.interval - lastIncrement; usleep(sleeptime); - m_sync.cont++; + cont++; msc2++; CLog::Log(LOGDEBUG, "CGLContextEGL::SwapBuffers: sync sleep: %ld", sleeptime); } @@ -485,11 +488,15 @@ void CGLContextEGL::SwapBuffers() usleep(sleeptime); msc2++; } - - m_sync.ust1 = ust1; - m_sync.ust2 = ust2; - m_sync.msc1 = msc1; - m_sync.msc2 = msc2; + { + CSingleLock lock(m_syncLock); + m_sync.ust1 = ust1; + m_sync.ust2 = ust2; + m_sync.msc1 = msc1; + m_sync.msc2 = msc2; + m_sync.interval = interval; + m_sync.cont = cont; + } } uint64_t CGLContextEGL::GetVblankTiming(uint64_t &msc, uint64_t &interval) @@ -500,6 +507,7 @@ uint64_t CGLContextEGL::GetVblankTiming(uint64_t &msc, uint64_t &interval) now = nowTs.tv_sec * 1000000000 + nowTs.tv_nsec; now /= 1000; + CSingleLock lock(m_syncLock); msc = m_sync.msc2; interval = (m_sync.cont > 5) ? m_sync.interval : m_sync.ust2 - m_sync.ust1; diff --git a/xbmc/windowing/X11/GLContextEGL.h b/xbmc/windowing/X11/GLContextEGL.h index 9dbb4bcc3c..80ad06050a 100644 --- a/xbmc/windowing/X11/GLContextEGL.h +++ b/xbmc/windowing/X11/GLContextEGL.h @@ -9,6 +9,7 @@ #pragma once #include "GLContext.h" +#include "threads/CriticalSection.h" #include "EGL/egl.h" #include "EGL/eglext.h" #include "EGL/eglextchromium.h" @@ -48,5 +49,7 @@ protected: uint64_t interval = 0; } m_sync; + CCriticalSection m_syncLock; + bool m_usePB = false; }; diff --git a/xbmc/windows/GUIWindowDebugInfo.cpp b/xbmc/windows/GUIWindowDebugInfo.cpp index 225fcb72fa..2f0e6426e6 100644 --- a/xbmc/windows/GUIWindowDebugInfo.cpp +++ b/xbmc/windows/GUIWindowDebugInfo.cpp @@ -55,6 +55,9 @@ bool CGUIWindowDebugInfo::OnMessage(CGUIMessage &message) delete m_layout; m_layout = nullptr; } + else if (message.GetMessage() == GUI_MSG_REFRESH_TIMER) + MarkDirtyRegion(); + return CGUIDialog::OnMessage(message); } |