2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
11 #include "CompileInfo.h"
13 #include "ServiceBroker.h"
14 #include "addons/AddonManager.h"
15 #include "addons/AddonVersion.h"
16 #include "addons/binary-addons/AddonDll.h"
17 #include "addons/kodi-dev-kit/include/kodi/General.h"
18 #include "application/ApplicationComponents.h"
19 #include "application/ApplicationPowerHandling.h"
20 #include "dialogs/GUIDialogKaiToast.h"
21 #include "input/keyboard/KeyboardLayout.h"
22 #include "input/keyboard/KeyboardLayoutManager.h"
23 #include "settings/Settings.h"
24 #include "settings/SettingsComponent.h"
25 #include "utils/CharsetConverter.h"
26 #include "utils/Digest.h"
27 #include "utils/LangCodeExpander.h"
28 #include "utils/MemUtils.h"
29 #include "utils/StringUtils.h"
30 #include "utils/log.h"
34 using namespace kodi
; // addon-dev-kit namespace
36 using UTILITY::CDigest
;
41 void Interface_General::Init(AddonGlobalInterface
* addonInterface
)
43 addonInterface
->toKodi
->kodi
= static_cast<AddonToKodiFuncTable_kodi
*>(malloc(sizeof(AddonToKodiFuncTable_kodi
)));
45 addonInterface
->toKodi
->kodi
->unknown_to_utf8
= unknown_to_utf8
;
46 addonInterface
->toKodi
->kodi
->get_language
= get_language
;
47 addonInterface
->toKodi
->kodi
->queue_notification
= queue_notification
;
48 addonInterface
->toKodi
->kodi
->get_md5
= get_md5
;
49 addonInterface
->toKodi
->kodi
->get_region
= get_region
;
50 addonInterface
->toKodi
->kodi
->get_free_mem
= get_free_mem
;
51 addonInterface
->toKodi
->kodi
->get_global_idle_time
= get_global_idle_time
;
52 addonInterface
->toKodi
->kodi
->is_addon_avilable
= is_addon_avilable
;
53 addonInterface
->toKodi
->kodi
->kodi_version
= kodi_version
;
54 addonInterface
->toKodi
->kodi
->get_current_skin_id
= get_current_skin_id
;
55 addonInterface
->toKodi
->kodi
->get_keyboard_layout
= get_keyboard_layout
;
56 addonInterface
->toKodi
->kodi
->change_keyboard_layout
= change_keyboard_layout
;
59 void Interface_General::DeInit(AddonGlobalInterface
* addonInterface
)
61 if (addonInterface
->toKodi
&& /* <-- needed as long as the old addon way is used */
62 addonInterface
->toKodi
->kodi
)
64 free(addonInterface
->toKodi
->kodi
);
65 addonInterface
->toKodi
->kodi
= nullptr;
69 char* Interface_General::unknown_to_utf8(void* kodiBase
, const char* source
, bool* ret
, bool failOnBadChar
)
71 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
72 if (!addon
|| !source
|| !ret
)
74 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', source='{}', ret='{}')",
75 __FUNCTION__
, kodiBase
, static_cast<const void*>(source
), static_cast<void*>(ret
));
80 *ret
= g_charsetConverter
.unknownToUTF8(source
, string
, failOnBadChar
);
81 char* buffer
= strdup(string
.c_str());
85 char* Interface_General::get_language(void* kodiBase
, int format
, bool region
)
87 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
90 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__
,
95 std::string string
= g_langInfo
.GetEnglishLanguageName();
98 case LANG_FMT_ISO_639_1
:
100 std::string langCode
;
101 g_LangCodeExpander
.ConvertToISO6391(string
, langCode
);
105 std::string region2Code
;
106 g_LangCodeExpander
.ConvertToISO6391(g_langInfo
.GetRegionLocale(), region2Code
);
107 if (!region2Code
.empty())
108 string
+= "-" + region2Code
;
112 case LANG_FMT_ISO_639_2
:
114 std::string langCode
;
115 g_LangCodeExpander
.ConvertToISO6392B(string
, langCode
);
119 std::string region3Code
;
120 g_LangCodeExpander
.ConvertToISO6392B(g_langInfo
.GetRegionLocale(), region3Code
);
121 if (!region3Code
.empty())
122 string
+= "-" + region3Code
;
126 case LANG_FMT_ENGLISH_NAME
:
130 string
+= "-" + g_langInfo
.GetCurrentRegion();
135 char* buffer
= strdup(string
.c_str());
139 bool Interface_General::queue_notification(void* kodiBase
, int type
, const char* header
,
140 const char* message
, const char* imageFile
,
141 unsigned int displayTime
, bool withSound
,
142 unsigned int messageTime
)
144 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
145 if (addon
== nullptr || message
== nullptr)
147 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', message='{}')",
148 __FUNCTION__
, kodiBase
, static_cast<const void*>(message
));
152 std::string usedHeader
;
153 if (header
&& strlen(header
) > 0)
156 usedHeader
= addon
->Name();
158 QueueMsg qtype
= static_cast<QueueMsg
>(type
);
160 if (qtype
!= QUEUE_OWN_STYLE
)
162 CGUIDialogKaiToast::eMessageType usedType
;
165 case QueueMsg::QUEUE_WARNING
:
166 usedType
= CGUIDialogKaiToast::Warning
;
168 CLog::Log(LOGDEBUG
, "Interface_General::{} - {} - Warning Message: '{}'", __FUNCTION__
,
169 addon
->Name(), message
);
171 case QueueMsg::QUEUE_ERROR
:
172 usedType
= CGUIDialogKaiToast::Error
;
174 CLog::Log(LOGDEBUG
, "Interface_General::{} - {} - Error Message : '{}'", __FUNCTION__
,
175 addon
->Name(), message
);
177 case QueueMsg::QUEUE_INFO
:
179 usedType
= CGUIDialogKaiToast::Info
;
181 CLog::Log(LOGDEBUG
, "Interface_General::{} - {} - Info Message : '{}'", __FUNCTION__
,
182 addon
->Name(), message
);
186 if (imageFile
&& strlen(imageFile
) > 0)
189 "Interface_General::{} - To use given image file '{}' must be type value set to "
191 __FUNCTION__
, imageFile
);
194 CGUIDialogKaiToast::QueueNotification(usedType
, usedHeader
, message
, 3000, withSound
);
198 CGUIDialogKaiToast::QueueNotification(imageFile
, usedHeader
, message
, displayTime
, withSound
, messageTime
);
203 void Interface_General::get_md5(void* kodiBase
, const char* text
, char* md5
)
205 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
206 if (addon
== nullptr || text
== nullptr)
208 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', text='{}')",
209 __FUNCTION__
, kodiBase
, static_cast<const void*>(text
));
213 std::string md5Int
= CDigest::Calculate(CDigest::Type::MD5
, std::string(text
));
214 strncpy(md5
, md5Int
.c_str(), 40);
217 char* Interface_General::get_region(void* kodiBase
, const char* id
)
219 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
220 if (addon
== nullptr || id
== nullptr)
222 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', id='{}')", __FUNCTION__
,
223 kodiBase
, static_cast<const void*>(id
));
228 if (StringUtils::CompareNoCase(id
, "datelong") == 0)
230 result
= g_langInfo
.GetDateFormat(true);
231 StringUtils::Replace(result
, "DDDD", "%A");
232 StringUtils::Replace(result
, "MMMM", "%B");
233 StringUtils::Replace(result
, "D", "%d");
234 StringUtils::Replace(result
, "YYYY", "%Y");
236 else if (StringUtils::CompareNoCase(id
, "dateshort") == 0)
238 result
= g_langInfo
.GetDateFormat(false);
239 StringUtils::Replace(result
, "MM", "%m");
240 StringUtils::Replace(result
, "DD", "%d");
241 #ifdef TARGET_WINDOWS
242 StringUtils::Replace(result
, "M", "%#m");
243 StringUtils::Replace(result
, "D", "%#d");
245 StringUtils::Replace(result
, "M", "%-m");
246 StringUtils::Replace(result
, "D", "%-d");
248 StringUtils::Replace(result
, "YYYY", "%Y");
250 else if (StringUtils::CompareNoCase(id
, "tempunit") == 0)
251 result
= g_langInfo
.GetTemperatureUnitString();
252 else if (StringUtils::CompareNoCase(id
, "speedunit") == 0)
253 result
= g_langInfo
.GetSpeedUnitString();
254 else if (StringUtils::CompareNoCase(id
, "time") == 0)
256 result
= g_langInfo
.GetTimeFormat();
257 StringUtils::Replace(result
, "H", "%H");
258 StringUtils::Replace(result
, "h", "%I");
259 StringUtils::Replace(result
, "mm", "%M");
260 StringUtils::Replace(result
, "ss", "%S");
261 StringUtils::Replace(result
, "xx", "%p");
263 else if (StringUtils::CompareNoCase(id
, "meridiem") == 0)
264 result
= StringUtils::Format("{}/{}", g_langInfo
.GetMeridiemSymbol(MeridiemSymbolAM
),
265 g_langInfo
.GetMeridiemSymbol(MeridiemSymbolPM
));
268 CLog::Log(LOGERROR
, "Interface_General::{} - add-on '{}' requests invalid id '{}'",
269 __FUNCTION__
, addon
->Name(), id
);
273 char* buffer
= strdup(result
.c_str());
277 void Interface_General::get_free_mem(void* kodiBase
, long* free
, long* total
, bool as_bytes
)
279 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
280 if (addon
== nullptr || free
== nullptr || total
== nullptr)
282 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', free='{}', total='{}')",
283 __FUNCTION__
, kodiBase
, static_cast<void*>(free
), static_cast<void*>(total
));
287 KODI::MEMORY::MemoryStatus stat
;
288 KODI::MEMORY::GetMemoryStatus(&stat
);
289 *free
= static_cast<long>(stat
.availPhys
);
290 *total
= static_cast<long>(stat
.totalPhys
);
293 *free
= *free
/ ( 1024 * 1024 );
294 *total
= *total
/ ( 1024 * 1024 );
298 int Interface_General::get_global_idle_time(void* kodiBase
)
300 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
301 if (addon
== nullptr)
303 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__
,
308 auto& components
= CServiceBroker::GetAppComponents();
309 const auto appPower
= components
.GetComponent
<CApplicationPowerHandling
>();
310 return appPower
->GlobalIdleTime();
313 bool Interface_General::is_addon_avilable(void* kodiBase
,
318 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
319 if (addon
== nullptr || id
== nullptr || version
== nullptr || enabled
== nullptr)
323 "Interface_General::{} - invalid data (addon='{}', id='{}', version='{}', enabled='{}')",
324 __FUNCTION__
, kodiBase
, static_cast<const void*>(id
), static_cast<void*>(version
),
325 static_cast<void*>(enabled
));
330 if (!CServiceBroker::GetAddonMgr().GetAddon(id
, addonInfo
, OnlyEnabled::CHOICE_NO
))
333 *version
= strdup(addonInfo
->Version().asString().c_str());
334 *enabled
= !CServiceBroker::GetAddonMgr().IsAddonDisabled(id
);
338 void Interface_General::kodi_version(void* kodiBase
, char** compile_name
, int* major
, int* minor
, char** revision
, char** tag
, char** tagversion
)
340 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
341 if (addon
== nullptr || compile_name
== nullptr || major
== nullptr || minor
== nullptr ||
342 revision
== nullptr || tag
== nullptr || tagversion
== nullptr)
345 "Interface_General::{} - invalid data (addon='{}', compile_name='{}', major='{}', "
346 "minor='{}', revision='{}', tag='{}', tagversion='{}')",
347 __FUNCTION__
, kodiBase
, static_cast<void*>(compile_name
), static_cast<void*>(major
),
348 static_cast<void*>(minor
), static_cast<void*>(revision
), static_cast<void*>(tag
),
349 static_cast<void*>(tagversion
));
353 *compile_name
= strdup(CCompileInfo::GetAppName());
354 *major
= CCompileInfo::GetMajor();
355 *minor
= CCompileInfo::GetMinor();
356 *revision
= strdup(CCompileInfo::GetSCMID());
357 std::string tagStr
= CCompileInfo::GetSuffix();
358 if (StringUtils::StartsWithNoCase(tagStr
, "alpha"))
360 *tag
= strdup("alpha");
361 *tagversion
= strdup(StringUtils::Mid(tagStr
, 5).c_str());
363 else if (StringUtils::StartsWithNoCase(tagStr
, "beta"))
365 *tag
= strdup("beta");
366 *tagversion
= strdup(StringUtils::Mid(tagStr
, 4).c_str());
368 else if (StringUtils::StartsWithNoCase(tagStr
, "rc"))
370 *tag
= strdup("releasecandidate");
371 *tagversion
= strdup(StringUtils::Mid(tagStr
, 2).c_str());
373 else if (tagStr
.empty())
374 *tag
= strdup("stable");
376 *tag
= strdup("prealpha");
379 char* Interface_General::get_current_skin_id(void* kodiBase
)
381 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
382 if (addon
== nullptr)
384 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}')", __FUNCTION__
,
389 return strdup(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN
).c_str());
392 bool Interface_General::get_keyboard_layout(void* kodiBase
, char** layout_name
, int modifier_key
, AddonKeyboardKeyTable
* c_layout
)
394 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
395 if (addon
== nullptr || c_layout
== nullptr || layout_name
== nullptr)
398 "Interface_General::{} - invalid data (addon='{}', c_layout='{}', layout_name='{}')",
399 __FUNCTION__
, kodiBase
, static_cast<void*>(c_layout
),
400 static_cast<void*>(layout_name
));
404 std::string activeLayout
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT
);
406 KEYBOARD::CKeyboardLayout layout
;
407 if (!CServiceBroker::GetKeyboardLayoutManager()->GetLayout(activeLayout
, layout
))
410 *layout_name
= strdup(layout
.GetName().c_str());
412 unsigned int modifiers
= KEYBOARD::CKeyboardLayout::ModifierKeyNone
;
413 if (modifier_key
& STD_KB_MODIFIER_KEY_SHIFT
)
414 modifiers
|= KEYBOARD::CKeyboardLayout::ModifierKeyShift
;
415 if (modifier_key
& STD_KB_MODIFIER_KEY_SYMBOL
)
416 modifiers
|= KEYBOARD::CKeyboardLayout::ModifierKeySymbol
;
418 for (unsigned int row
= 0; row
< STD_KB_BUTTONS_MAX_ROWS
; row
++)
420 for (unsigned int column
= 0; column
< STD_KB_BUTTONS_PER_ROW
; column
++)
422 std::string label
= layout
.GetCharAt(row
, column
, modifiers
);
423 c_layout
->keys
[row
][column
] = strdup(label
.c_str());
430 bool Interface_General::change_keyboard_layout(void* kodiBase
, char** layout_name
)
432 CAddonDll
* addon
= static_cast<CAddonDll
*>(kodiBase
);
433 if (addon
== nullptr || layout_name
== nullptr)
435 CLog::Log(LOGERROR
, "Interface_General::{} - invalid data (addon='{}', layout_name='{}')",
436 __FUNCTION__
, kodiBase
, static_cast<void*>(layout_name
));
440 std::vector
<KEYBOARD::CKeyboardLayout
> layouts
;
441 unsigned int currentLayout
= 0;
443 const KEYBOARD::KeyboardLayouts
& keyboardLayouts
=
444 CServiceBroker::GetKeyboardLayoutManager()->GetLayouts();
445 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
446 std::vector
<CVariant
> layoutNames
= settings
->GetList(CSettings::SETTING_LOCALE_KEYBOARDLAYOUTS
);
447 std::string activeLayout
= settings
->GetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT
);
449 for (const auto& layoutName
: layoutNames
)
451 const auto keyboardLayout
= keyboardLayouts
.find(layoutName
.asString());
452 if (keyboardLayout
!= keyboardLayouts
.end())
454 layouts
.emplace_back(keyboardLayout
->second
);
455 if (layoutName
.asString() == activeLayout
)
456 currentLayout
= layouts
.size() - 1;
461 if (currentLayout
>= layouts
.size())
463 KEYBOARD::CKeyboardLayout layout
=
464 layouts
.empty() ? KEYBOARD::CKeyboardLayout() : layouts
[currentLayout
];
465 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT
, layout
.GetName());
467 *layout_name
= strdup(layout
.GetName().c_str());
471 } /* namespace ADDON */