2 * Copyright (C) 2005-2020 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 "GUIUserMessages.h"
12 #include "addons/AddonManager.h"
13 #include "addons/addoninfo/AddonInfo.h"
14 #include "addons/addoninfo/AddonType.h"
15 #include "addons/binary-addons/AddonDll.h"
16 #include "addons/gui/GUIDialogAddonSettings.h"
17 #include "addons/settings/AddonSettings.h"
18 #include "application/Application.h"
19 #include "filesystem/Directory.h"
20 #include "filesystem/SpecialProtocol.h"
21 #include "guilib/GUIComponent.h"
22 #include "guilib/GUIWindowManager.h"
23 #include "guilib/LocalizeStrings.h"
24 #include "settings/lib/Setting.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "utils/log.h"
29 // "C" interface addon callback handle classes
30 #include "AudioEngine.h"
31 #include "Filesystem.h"
34 #include "gui/General.h"
39 std::vector
<ADDON_GET_INTERFACE_FN
> Interface_Base::s_registeredInterfaces
;
41 bool Interface_Base::InitInterface(CAddonDll
* addon
,
42 AddonGlobalInterface
& addonInterface
,
43 KODI_ADDON_INSTANCE_STRUCT
* firstKodiInstance
)
47 addonInterface
.addonBase
= nullptr;
48 addonInterface
.globalSingleInstance
= nullptr;
49 addonInterface
.firstKodiInstance
= firstKodiInstance
;
51 // Create function list from kodi to addon, generated with malloc to have
52 // compatible with other versions
53 addonInterface
.toKodi
= new AddonToKodiFuncTable_Addon();
54 addonInterface
.toKodi
->kodiBase
= addon
;
55 addonInterface
.toKodi
->addon_log_msg
= addon_log_msg
;
56 addonInterface
.toKodi
->free_string
= free_string
;
57 addonInterface
.toKodi
->free_string_array
= free_string_array
;
59 addonInterface
.toKodi
->kodi_addon
= new AddonToKodiFuncTable_kodi_addon();
60 addonInterface
.toKodi
->kodi_addon
->get_addon_path
= get_addon_path
;
61 addonInterface
.toKodi
->kodi_addon
->get_lib_path
= get_lib_path
;
62 addonInterface
.toKodi
->kodi_addon
->get_user_path
= get_user_path
;
63 addonInterface
.toKodi
->kodi_addon
->get_temp_path
= get_temp_path
;
64 addonInterface
.toKodi
->kodi_addon
->get_localized_string
= get_localized_string
;
65 addonInterface
.toKodi
->kodi_addon
->open_settings_dialog
= open_settings_dialog
;
66 addonInterface
.toKodi
->kodi_addon
->is_setting_using_default
= is_setting_using_default
;
67 addonInterface
.toKodi
->kodi_addon
->get_setting_bool
= get_setting_bool
;
68 addonInterface
.toKodi
->kodi_addon
->get_setting_int
= get_setting_int
;
69 addonInterface
.toKodi
->kodi_addon
->get_setting_float
= get_setting_float
;
70 addonInterface
.toKodi
->kodi_addon
->get_setting_string
= get_setting_string
;
71 addonInterface
.toKodi
->kodi_addon
->set_setting_bool
= set_setting_bool
;
72 addonInterface
.toKodi
->kodi_addon
->set_setting_int
= set_setting_int
;
73 addonInterface
.toKodi
->kodi_addon
->set_setting_float
= set_setting_float
;
74 addonInterface
.toKodi
->kodi_addon
->set_setting_string
= set_setting_string
;
75 addonInterface
.toKodi
->kodi_addon
->get_addon_info
= get_addon_info
;
76 addonInterface
.toKodi
->kodi_addon
->get_type_version
= get_type_version
;
77 addonInterface
.toKodi
->kodi_addon
->get_interface
= get_interface
;
79 // Related parts becomes set from addon headers, make here to nullptr to allow
80 // checks for right set of them
81 addonInterface
.toAddon
= new KodiToAddonFuncTable_Addon();
83 // Init the other interfaces
84 Interface_General::Init(&addonInterface
);
85 Interface_AudioEngine::Init(&addonInterface
);
86 Interface_Filesystem::Init(&addonInterface
);
87 Interface_Network::Init(&addonInterface
);
88 Interface_GUIGeneral::Init(&addonInterface
);
93 void Interface_Base::DeInitInterface(AddonGlobalInterface
& addonInterface
)
95 Interface_GUIGeneral::DeInit(&addonInterface
);
96 Interface_Network::DeInit(&addonInterface
);
97 Interface_Filesystem::DeInit(&addonInterface
);
98 Interface_AudioEngine::DeInit(&addonInterface
);
99 Interface_General::DeInit(&addonInterface
);
101 if (addonInterface
.toKodi
)
102 delete addonInterface
.toKodi
->kodi_addon
;
103 delete addonInterface
.toKodi
;
104 delete addonInterface
.toAddon
;
108 void Interface_Base::RegisterInterface(ADDON_GET_INTERFACE_FN fn
)
110 s_registeredInterfaces
.push_back(fn
);
113 bool Interface_Base::UpdateSettingInActiveDialog(CAddonDll
* addon
,
114 AddonInstanceId instanceId
,
116 const std::string
& value
)
118 if (!CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_DIALOG_ADDON_SETTINGS
))
121 CGUIDialogAddonSettings
* dialog
=
122 CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogAddonSettings
>(
123 WINDOW_DIALOG_ADDON_SETTINGS
);
124 if (dialog
->GetCurrentAddonID() != addon
->ID())
127 CGUIMessage
message(GUI_MSG_SETTING_UPDATED
, 0, 0);
128 std::vector
<std::string
> params
;
129 params
.emplace_back(id
);
130 params
.push_back(value
);
131 message
.SetStringParams(params
);
132 message
.SetParam1(instanceId
);
133 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message
,
134 WINDOW_DIALOG_ADDON_SETTINGS
);
140 * @brief Addon to Kodi basic callbacks below
142 * The amount of functions here are hold so minimal as possible. Only parts
143 * where needed on nearly every add-on (e.g. addon_log_msg) are to add there.
145 * More specific parts like e.g. to open files should be added to a separate
150 void Interface_Base::addon_log_msg(const KODI_ADDON_BACKEND_HDL hdl
,
151 const int addonLogLevel
,
152 const char* strMessage
)
154 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
155 if (addon
== nullptr)
157 CLog::Log(LOGERROR
, "addon_log_msg(...) called with empty kodi instance pointer");
161 int logLevel
= LOGNONE
;
162 switch (addonLogLevel
)
164 case ADDON_LOG_DEBUG
:
170 case ADDON_LOG_WARNING
:
171 logLevel
= LOGWARNING
;
173 case ADDON_LOG_ERROR
:
176 case ADDON_LOG_FATAL
:
184 CLog::Log(logLevel
, "AddOnLog: {}: {}", addon
->ID(), strMessage
);
187 char* Interface_Base::get_type_version(const KODI_ADDON_BACKEND_HDL hdl
, int type
)
189 return strdup(kodi::addon::GetTypeVersion(type
));
192 char* Interface_Base::get_addon_path(const KODI_ADDON_BACKEND_HDL hdl
)
194 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
195 if (addon
== nullptr)
197 CLog::Log(LOGERROR
, "get_addon_path(...) called with empty kodi instance pointer");
201 return strdup(CSpecialProtocol::TranslatePath(addon
->Path()).c_str());
204 char* Interface_Base::get_lib_path(const KODI_ADDON_BACKEND_HDL hdl
)
206 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
207 if (addon
== nullptr)
209 CLog::Log(LOGERROR
, "get_lib_path(...) called with empty kodi instance pointer");
213 return strdup(CSpecialProtocol::TranslatePath("special://xbmcbinaddons/" + addon
->ID()).c_str());
216 char* Interface_Base::get_user_path(const KODI_ADDON_BACKEND_HDL hdl
)
218 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
219 if (addon
== nullptr)
221 CLog::Log(LOGERROR
, "get_user_path(...) called with empty kodi instance pointer");
225 return strdup(CSpecialProtocol::TranslatePath(addon
->Profile()).c_str());
228 char* Interface_Base::get_temp_path(const KODI_ADDON_BACKEND_HDL hdl
)
230 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
231 if (addon
== nullptr)
233 CLog::Log(LOGERROR
, "get_temp_path(...) called with empty kodi instance pointer");
237 std::string tempPath
=
238 URIUtils::AddFileToFolder(CServiceBroker::GetAddonMgr().GetTempAddonBasePath(), addon
->ID());
240 XFILE::CDirectory::Create(tempPath
);
242 return strdup(CSpecialProtocol::TranslatePath(tempPath
).c_str());
245 char* Interface_Base::get_localized_string(const KODI_ADDON_BACKEND_HDL hdl
, long label_id
)
247 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
250 CLog::Log(LOGERROR
, "get_localized_string(...) called with empty kodi instance pointer");
254 if (g_application
.m_bStop
)
257 std::string label
= g_localizeStrings
.GetAddonString(addon
->ID(), label_id
);
259 label
= g_localizeStrings
.Get(label_id
);
260 char* buffer
= strdup(label
.c_str());
264 char* Interface_Base::get_addon_info(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
)
266 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
267 if (addon
== nullptr || id
== nullptr)
269 CLog::Log(LOGERROR
, "get_addon_info(...) called with empty pointer");
274 if (StringUtils::CompareNoCase(id
, "author") == 0)
275 str
= addon
->Author();
276 else if (StringUtils::CompareNoCase(id
, "changelog") == 0)
277 str
= addon
->ChangeLog();
278 else if (StringUtils::CompareNoCase(id
, "description") == 0)
279 str
= addon
->Description();
280 else if (StringUtils::CompareNoCase(id
, "disclaimer") == 0)
281 str
= addon
->Disclaimer();
282 else if (StringUtils::CompareNoCase(id
, "fanart") == 0)
283 str
= addon
->FanArt();
284 else if (StringUtils::CompareNoCase(id
, "icon") == 0)
286 else if (StringUtils::CompareNoCase(id
, "id") == 0)
288 else if (StringUtils::CompareNoCase(id
, "name") == 0)
290 else if (StringUtils::CompareNoCase(id
, "path") == 0)
292 else if (StringUtils::CompareNoCase(id
, "profile") == 0)
293 str
= addon
->Profile();
294 else if (StringUtils::CompareNoCase(id
, "summary") == 0)
295 str
= addon
->Summary();
296 else if (StringUtils::CompareNoCase(id
, "type") == 0)
297 str
= ADDON::CAddonInfo::TranslateType(addon
->Type());
298 else if (StringUtils::CompareNoCase(id
, "version") == 0)
299 str
= addon
->Version().asString();
302 CLog::Log(LOGERROR
, "Interface_Base::{} - add-on '{}' requests invalid id '{}'", __func__
,
307 char* buffer
= strdup(str
.c_str());
311 bool Interface_Base::open_settings_dialog(const KODI_ADDON_BACKEND_HDL hdl
)
313 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
314 if (addon
== nullptr)
316 CLog::Log(LOGERROR
, "open_settings_dialog(...) called with empty kodi instance pointer");
320 // show settings dialog
322 if (!CServiceBroker::GetAddonMgr().GetAddon(addon
->ID(), addonInfo
, OnlyEnabled::CHOICE_YES
))
324 CLog::Log(LOGERROR
, "Interface_Base::{} - Could not get addon information for '{}'", __func__
,
329 return CGUIDialogAddonSettings::ShowForAddon(addonInfo
);
332 bool Interface_Base::is_setting_using_default(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
)
334 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
335 if (addon
== nullptr || id
== nullptr)
337 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__
, hdl
,
338 static_cast<const void*>(id
));
343 if (!addon
->HasSettings())
345 CLog::Log(LOGERROR
, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__
,
350 auto setting
= addon
->GetSettings()->GetSetting(id
);
351 if (setting
== nullptr)
353 CLog::Log(LOGERROR
, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__
, id
,
358 return setting
->IsDefault();
361 bool Interface_Base::get_setting_bool(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
, bool* value
)
363 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
364 if (addon
== nullptr || id
== nullptr || value
== nullptr)
366 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')",
367 __func__
, hdl
, static_cast<const void*>(id
), static_cast<void*>(value
));
372 if (!addon
->HasSettings())
374 CLog::Log(LOGERROR
, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__
,
379 auto setting
= addon
->GetSettings()->GetSetting(id
);
380 if (setting
== nullptr)
382 CLog::Log(LOGERROR
, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__
, id
,
387 if (setting
->GetType() != SettingType::Boolean
)
389 CLog::Log(LOGERROR
, "Interface_Base::{} - setting '{}' is not a boolean in '{}'", __func__
, id
,
394 *value
= std::static_pointer_cast
<CSettingBool
>(setting
)->GetValue();
398 bool Interface_Base::get_setting_int(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
, int* value
)
400 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
401 if (addon
== nullptr || id
== nullptr || value
== nullptr)
403 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')",
404 __func__
, hdl
, static_cast<const void*>(id
), static_cast<void*>(value
));
409 if (!addon
->HasSettings())
411 CLog::Log(LOGERROR
, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__
,
416 auto setting
= addon
->GetSettings()->GetSetting(id
);
417 if (setting
== nullptr)
419 CLog::Log(LOGERROR
, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__
, id
,
424 if (setting
->GetType() != SettingType::Integer
&& setting
->GetType() != SettingType::Number
)
426 CLog::Log(LOGERROR
, "Interface_Base::{} - setting '{}' is not a integer in '{}'", __func__
, id
,
431 if (setting
->GetType() == SettingType::Integer
)
432 *value
= std::static_pointer_cast
<CSettingInt
>(setting
)->GetValue();
434 *value
= static_cast<int>(std::static_pointer_cast
<CSettingNumber
>(setting
)->GetValue());
438 bool Interface_Base::get_setting_float(const KODI_ADDON_BACKEND_HDL hdl
,
442 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
443 if (addon
== nullptr || id
== nullptr || value
== nullptr)
445 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')",
446 __func__
, hdl
, static_cast<const void*>(id
), static_cast<void*>(value
));
451 if (!addon
->HasSettings())
453 CLog::Log(LOGERROR
, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__
,
458 auto setting
= addon
->GetSettings()->GetSetting(id
);
459 if (setting
== nullptr)
461 CLog::Log(LOGERROR
, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__
, id
,
466 if (setting
->GetType() != SettingType::Number
)
468 CLog::Log(LOGERROR
, "Interface_Base::{} - setting '{}' is not a number in '{}'", __func__
, id
,
473 *value
= static_cast<float>(std::static_pointer_cast
<CSettingNumber
>(setting
)->GetValue());
477 bool Interface_Base::get_setting_string(const KODI_ADDON_BACKEND_HDL hdl
,
481 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
482 if (addon
== nullptr || id
== nullptr || value
== nullptr)
484 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')",
485 __func__
, hdl
, static_cast<const void*>(id
), static_cast<void*>(value
));
490 if (!addon
->HasSettings())
492 CLog::Log(LOGERROR
, "Interface_Base::{} - couldn't get settings for add-on '{}'", __func__
,
497 auto setting
= addon
->GetSettings()->GetSetting(id
);
498 if (setting
== nullptr)
500 CLog::Log(LOGERROR
, "Interface_Base::{} - can't find setting '{}' in '{}'", __func__
, id
,
505 if (setting
->GetType() != SettingType::String
)
507 CLog::Log(LOGERROR
, "Interface_Base::{} - setting '{}' is not a string in '{}'", __func__
, id
,
512 *value
= strdup(std::static_pointer_cast
<CSettingString
>(setting
)->GetValue().c_str());
516 bool Interface_Base::set_setting_bool(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
, bool value
)
518 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
519 if (addon
== nullptr || id
== nullptr)
521 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__
, hdl
,
522 static_cast<const void*>(id
));
527 if (Interface_Base::UpdateSettingInActiveDialog(addon
, ADDON_SETTINGS_ID
, id
,
528 value
? "true" : "false"))
531 if (!addon
->UpdateSettingBool(id
, value
))
533 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid setting type", __func__
);
537 addon
->SaveSettings();
542 bool Interface_Base::set_setting_int(const KODI_ADDON_BACKEND_HDL hdl
, const char* id
, int value
)
544 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
545 if (addon
== nullptr || id
== nullptr)
547 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__
, hdl
,
548 static_cast<const void*>(id
));
553 if (Interface_Base::UpdateSettingInActiveDialog(addon
, ADDON_SETTINGS_ID
, id
,
554 std::to_string(value
)))
557 if (!addon
->UpdateSettingInt(id
, value
))
559 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid setting type", __func__
);
563 addon
->SaveSettings();
568 bool Interface_Base::set_setting_float(const KODI_ADDON_BACKEND_HDL hdl
,
572 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
573 if (addon
== nullptr || id
== nullptr)
575 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}')", __func__
, hdl
,
576 static_cast<const void*>(id
));
581 if (Interface_Base::UpdateSettingInActiveDialog(addon
, ADDON_SETTINGS_ID
, id
,
582 StringUtils::Format("{:f}", value
)))
585 if (!addon
->UpdateSettingNumber(id
, static_cast<double>(value
)))
587 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid setting type", __func__
);
591 addon
->SaveSettings();
596 bool Interface_Base::set_setting_string(const KODI_ADDON_BACKEND_HDL hdl
,
600 CAddonDll
* addon
= static_cast<CAddonDll
*>(hdl
);
601 if (addon
== nullptr || id
== nullptr || value
== nullptr)
603 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid data (addon='{}', id='{}', value='{}')",
604 __func__
, hdl
, static_cast<const void*>(id
), static_cast<const void*>(value
));
609 if (Interface_Base::UpdateSettingInActiveDialog(addon
, ADDON_SETTINGS_ID
, id
, value
))
612 if (!addon
->UpdateSettingString(id
, value
))
614 CLog::Log(LOGERROR
, "Interface_Base::{} - invalid setting type", __func__
);
618 addon
->SaveSettings();
623 void Interface_Base::free_string(const KODI_ADDON_BACKEND_HDL hdl
, char* str
)
629 void Interface_Base::free_string_array(const KODI_ADDON_BACKEND_HDL hdl
,
635 for (int i
= 0; i
< numElements
; ++i
)
643 void* Interface_Base::get_interface(const KODI_ADDON_BACKEND_HDL hdl
,
647 if (!name
|| !version
)
650 void* retval(nullptr);
652 for (auto fn
: s_registeredInterfaces
)
653 if ((retval
= fn(name
, version
)))