1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "addons/kodi-dev-kit/include/kodi/gui/Window.h"
10
11 #include "Application.h"
12 #include "FileItem.h"
13 #include "GUITranslator.h"
14 #include "General.h"
15 #include "ServiceBroker.h"
16 #include "Window.h"
17 #include "addons/Skin.h"
18 #include "addons/binary-addons/AddonDll.h"
19 #include "controls/Rendering.h"
20 #include "filesystem/File.h"
21 #include "guilib/GUIComponent.h"
22 #include "guilib/GUIRenderingControl.h"
23 #include "guilib/GUIWindowManager.h"
24 #include "guilib/TextureManager.h"
25 #include "input/Key.h"
26 #include "messaging/ApplicationMessenger.h"
27 #include "utils/StringUtils.h"
28 #include "utils/URIUtils.h"
29 #include "utils/Variant.h"
30 #include "utils/log.h"
31
32 using namespace ADDON;
33 using namespace KODI::MESSAGING;
34
35 namespace ADDON
36 {
37
Init(AddonGlobalInterface * addonInterface)38 void Interface_GUIWindow::Init(AddonGlobalInterface* addonInterface)
39 {
40 addonInterface->toKodi->kodi_gui->window = new AddonToKodiFuncTable_kodi_gui_window();
41
42 /* Window creation functions */
43 addonInterface->toKodi->kodi_gui->window->create = create;
44 addonInterface->toKodi->kodi_gui->window->destroy = destroy;
45 addonInterface->toKodi->kodi_gui->window->set_callbacks = set_callbacks;
46 addonInterface->toKodi->kodi_gui->window->show = show;
47 addonInterface->toKodi->kodi_gui->window->close = close;
48 addonInterface->toKodi->kodi_gui->window->do_modal = do_modal;
49
50 /* Window control functions */
51 addonInterface->toKodi->kodi_gui->window->set_focus_id = set_focus_id;
52 addonInterface->toKodi->kodi_gui->window->get_focus_id = get_focus_id;
53 addonInterface->toKodi->kodi_gui->window->set_control_label = set_control_label;
54 addonInterface->toKodi->kodi_gui->window->set_control_visible = set_control_visible;
55 addonInterface->toKodi->kodi_gui->window->set_control_selected = set_control_selected;
56
57 /* Window property functions */
58 addonInterface->toKodi->kodi_gui->window->set_property = set_property;
59 addonInterface->toKodi->kodi_gui->window->set_property_int = set_property_int;
60 addonInterface->toKodi->kodi_gui->window->set_property_bool = set_property_bool;
61 addonInterface->toKodi->kodi_gui->window->set_property_double = set_property_double;
62 addonInterface->toKodi->kodi_gui->window->get_property = get_property;
63 addonInterface->toKodi->kodi_gui->window->get_property_int = get_property_int;
64 addonInterface->toKodi->kodi_gui->window->get_property_bool = get_property_bool;
65 addonInterface->toKodi->kodi_gui->window->get_property_double = get_property_double;
66 addonInterface->toKodi->kodi_gui->window->clear_properties = clear_properties;
67 addonInterface->toKodi->kodi_gui->window->clear_property = clear_property;
68
69 /* List item functions */
70 addonInterface->toKodi->kodi_gui->window->clear_item_list = clear_item_list;
71 addonInterface->toKodi->kodi_gui->window->add_list_item = add_list_item;
72 addonInterface->toKodi->kodi_gui->window->remove_list_item_from_position =
73 remove_list_item_from_position;
74 addonInterface->toKodi->kodi_gui->window->remove_list_item = remove_list_item;
75 addonInterface->toKodi->kodi_gui->window->get_list_item = get_list_item;
76 addonInterface->toKodi->kodi_gui->window->set_current_list_position = set_current_list_position;
77 addonInterface->toKodi->kodi_gui->window->get_current_list_position = get_current_list_position;
78 addonInterface->toKodi->kodi_gui->window->get_list_size = get_list_size;
79 addonInterface->toKodi->kodi_gui->window->set_container_property = set_container_property;
80 addonInterface->toKodi->kodi_gui->window->set_container_content = set_container_content;
81 addonInterface->toKodi->kodi_gui->window->get_current_container_id = get_current_container_id;
82
83 /* Various functions */
84 addonInterface->toKodi->kodi_gui->window->mark_dirty_region = mark_dirty_region;
85
86 /* GUI control access functions */
87 addonInterface->toKodi->kodi_gui->window->get_control_button = get_control_button;
88 addonInterface->toKodi->kodi_gui->window->get_control_edit = get_control_edit;
89 addonInterface->toKodi->kodi_gui->window->get_control_fade_label = get_control_fade_label;
90 addonInterface->toKodi->kodi_gui->window->get_control_image = get_control_image;
91 addonInterface->toKodi->kodi_gui->window->get_control_label = get_control_label;
92 addonInterface->toKodi->kodi_gui->window->get_control_progress = get_control_progress;
93 addonInterface->toKodi->kodi_gui->window->get_control_radio_button = get_control_radio_button;
94 addonInterface->toKodi->kodi_gui->window->get_control_render_addon = get_control_render_addon;
95 addonInterface->toKodi->kodi_gui->window->get_control_settings_slider =
96 get_control_settings_slider;
97 addonInterface->toKodi->kodi_gui->window->get_control_slider = get_control_slider;
98 addonInterface->toKodi->kodi_gui->window->get_control_spin = get_control_spin;
99 addonInterface->toKodi->kodi_gui->window->get_control_text_box = get_control_text_box;
100 }
101
DeInit(AddonGlobalInterface * addonInterface)102 void Interface_GUIWindow::DeInit(AddonGlobalInterface* addonInterface)
103 {
104 delete addonInterface->toKodi->kodi_gui->window;
105 }
106
107 /*!
108 * Window creation functions
109 */
110 //@{
create(KODI_HANDLE kodiBase,const char * xml_filename,const char * default_skin,bool as_dialog,bool is_media)111 KODI_GUI_WINDOW_HANDLE Interface_GUIWindow::create(KODI_HANDLE kodiBase,
112 const char* xml_filename,
113 const char* default_skin,
114 bool as_dialog,
115 bool is_media)
116 {
117 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
118 if (!addon || !xml_filename || !default_skin)
119 {
120 CLog::Log(LOGERROR,
121 "Interface_GUIWindow::{} - invalid handler data (xml_filename='{}', "
122 "default_skin='{}') on addon '{}'",
123 __func__, static_cast<const void*>(xml_filename),
124 static_cast<const void*>(default_skin), addon ? addon->ID() : "unknown");
125 return nullptr;
126 }
127
128 if (as_dialog && is_media)
129 {
130 CLog::Log(LOGWARNING,
131 "Interface_GUIWindow::{}: {}/{} - addon tries to create dialog as media window who "
132 "not allowed, contact Developer '{}' of this addon",
133 __func__, CAddonInfo::TranslateType(addon->Type()), addon->Name(), addon->Author());
134 }
135
136 RESOLUTION_INFO res;
137 std::string strSkinPath = g_SkinInfo->GetSkinPath(xml_filename, &res);
138
139 if (!XFILE::CFile::Exists(strSkinPath))
140 {
141 std::string str("none");
142 ADDON::AddonInfoPtr addonInfo = std::make_shared<ADDON::CAddonInfo>(str, ADDON::ADDON_SKIN);
143
144 // Check for the matching folder for the skin in the fallback skins folder
145 std::string fallbackPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "skins");
146 std::string basePath = URIUtils::AddFileToFolder(fallbackPath, g_SkinInfo->ID());
147
148 strSkinPath = g_SkinInfo->GetSkinPath(xml_filename, &res, basePath);
149
150 // Check for the matching folder for the skin in the fallback skins folder (if it exists)
151 if (XFILE::CFile::Exists(basePath))
152 {
153 addonInfo->SetPath(basePath);
154 const std::shared_ptr<ADDON::CSkinInfo> skinInfo =
155 std::make_shared<ADDON::CSkinInfo>(addonInfo, res);
156 skinInfo->Start();
157 strSkinPath = skinInfo->GetSkinPath(xml_filename, &res);
158 }
159
160 if (!XFILE::CFile::Exists(strSkinPath))
161 {
162 // Finally fallback to the DefaultSkin as it didn't exist in either the Kodi Skin folder or the fallback skin folder
163 addonInfo->SetPath(URIUtils::AddFileToFolder(fallbackPath, default_skin));
164 const std::shared_ptr<ADDON::CSkinInfo> skinInfo =
165 std::make_shared<ADDON::CSkinInfo>(addonInfo, res);
166
167 skinInfo->Start();
168 strSkinPath = skinInfo->GetSkinPath(xml_filename, &res);
169 if (!XFILE::CFile::Exists(strSkinPath))
170 {
171 CLog::Log(LOGERROR,
172 "Interface_GUIWindow::{}: {}/{} - XML File '{}' for Window is missing, contact "
173 "Developer '{}' of this addon",
174 __func__, CAddonInfo::TranslateType(addon->Type()), addon->Name(), strSkinPath,
175 addon->Author());
176 return nullptr;
177 }
178 }
179 }
180
181 int id = GetNextAvailableWindowId();
182 if (id < 0)
183 return nullptr;
184
185 CGUIWindow* window;
186 if (!as_dialog)
187 window = new CGUIAddonWindow(id, strSkinPath, addon, is_media);
188 else
189 window = new CGUIAddonWindowDialog(id, strSkinPath, addon);
190
191 Interface_GUIGeneral::lock();
192 CServiceBroker::GetGUI()->GetWindowManager().Add(window);
193 Interface_GUIGeneral::unlock();
194
195 if (!CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id))
196 {
197 CLog::Log(LOGERROR,
198 "Interface_GUIWindow::{} - Requested window id '{}' does not exist for addon '{}'",
199 __func__, id, addon->ID());
200 delete window;
201 return nullptr;
202 }
203 window->SetCoordsRes(res);
204 return window;
205 }
206
destroy(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)207 void Interface_GUIWindow::destroy(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
208 {
209 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
210 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
211 if (!addon || !pAddonWindow)
212 {
213 CLog::Log(LOGERROR,
214 "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'",
215 __func__, handle, addon ? addon->ID() : "unknown");
216 return;
217 }
218
219 Interface_GUIGeneral::lock();
220 CGUIWindow* pWindow =
221 CServiceBroker::GetGUI()->GetWindowManager().GetWindow(pAddonWindow->GetID());
222 if (pWindow)
223 {
224 // first change to an existing window
225 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == pAddonWindow->GetID() &&
226 !g_application.m_bStop)
227 {
228 if (CServiceBroker::GetGUI()->GetWindowManager().GetWindow(pAddonWindow->m_oldWindowId))
229 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->m_oldWindowId);
230 else // old window does not exist anymore, switch to home
231 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_HOME);
232 }
233 // Free any window properties
234 pAddonWindow->ClearProperties();
235 // free the window's resources and unload it (free all guicontrols)
236 pAddonWindow->FreeResources(true);
237
238 CServiceBroker::GetGUI()->GetWindowManager().Remove(pAddonWindow->GetID());
239 }
240 delete pAddonWindow;
241 Interface_GUIGeneral::unlock();
242 }
243
set_callbacks(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,KODI_GUI_CLIENT_HANDLE clienthandle,bool (* CBOnInit)(KODI_GUI_CLIENT_HANDLE),bool (* CBOnFocus)(KODI_GUI_CLIENT_HANDLE,int),bool (* CBOnClick)(KODI_GUI_CLIENT_HANDLE,int),bool (* CBOnAction)(KODI_GUI_CLIENT_HANDLE,ADDON_ACTION),void (* CBGetContextButtons)(KODI_GUI_CLIENT_HANDLE,int,gui_context_menu_pair *,unsigned int *),bool (* CBOnContextButton)(KODI_GUI_CLIENT_HANDLE,int,unsigned int))244 void Interface_GUIWindow::set_callbacks(
245 KODI_HANDLE kodiBase,
246 KODI_GUI_WINDOW_HANDLE handle,
247 KODI_GUI_CLIENT_HANDLE clienthandle,
248 bool (*CBOnInit)(KODI_GUI_CLIENT_HANDLE),
249 bool (*CBOnFocus)(KODI_GUI_CLIENT_HANDLE, int),
250 bool (*CBOnClick)(KODI_GUI_CLIENT_HANDLE, int),
251 bool (*CBOnAction)(KODI_GUI_CLIENT_HANDLE, ADDON_ACTION),
252 void (*CBGetContextButtons)(KODI_GUI_CLIENT_HANDLE, int, gui_context_menu_pair*, unsigned int*),
253 bool (*CBOnContextButton)(KODI_GUI_CLIENT_HANDLE, int, unsigned int))
254 {
255 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
256 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
257 if (!addon || !pAddonWindow || !clienthandle)
258 {
259 CLog::Log(LOGERROR,
260 "Interface_GUIWindow::{} - invalid handler data (handle='{}', clienthandle='{}') "
261 "on addon '{}'",
262 __func__, handle, clienthandle, addon ? addon->ID() : "unknown");
263 return;
264 }
265
266 Interface_GUIGeneral::lock();
267 pAddonWindow->m_clientHandle = clienthandle;
268 pAddonWindow->CBOnInit = CBOnInit;
269 pAddonWindow->CBOnClick = CBOnClick;
270 pAddonWindow->CBOnFocus = CBOnFocus;
271 pAddonWindow->CBOnAction = CBOnAction;
272 pAddonWindow->CBGetContextButtons = CBGetContextButtons;
273 pAddonWindow->CBOnContextButton = CBOnContextButton;
274 Interface_GUIGeneral::unlock();
275 }
276
show(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)277 bool Interface_GUIWindow::show(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
278 {
279 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
280 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
281 if (!addon || !pAddonWindow)
282 {
283 CLog::Log(LOGERROR,
284 "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'",
285 __func__, handle, addon ? addon->ID() : "unknown");
286 return false;
287 }
288
289 if (pAddonWindow->m_oldWindowId != pAddonWindow->m_windowId &&
290 pAddonWindow->m_windowId != CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())
291 pAddonWindow->m_oldWindowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
292
293 Interface_GUIGeneral::lock();
294 if (pAddonWindow->IsDialog())
295 dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(true, false);
296 else
297 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->GetID());
298 Interface_GUIGeneral::unlock();
299
300 return true;
301 }
302
close(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)303 bool Interface_GUIWindow::close(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
304 {
305 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
306 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
307 if (!addon || !pAddonWindow)
308 {
309 CLog::Log(LOGERROR,
310 "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'",
311 __func__, handle, addon ? addon->ID() : "unknown");
312 return false;
313 }
314
315 pAddonWindow->PulseActionEvent();
316
317 Interface_GUIGeneral::lock();
318
319 // if it's a dialog, we have to close it a bit different
320 if (pAddonWindow->IsDialog())
321 dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(false);
322 else
323 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->m_oldWindowId);
324 pAddonWindow->m_oldWindowId = 0;
325
326 Interface_GUIGeneral::unlock();
327
328 return true;
329 }
330
do_modal(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)331 bool Interface_GUIWindow::do_modal(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
332 {
333 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
334 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
335 if (!addon || !pAddonWindow)
336 {
337 CLog::Log(LOGERROR,
338 "Interface_GUIWindow::{} - invalid handler data (handle='{}') on addon '{}'",
339 __func__, handle, addon ? addon->ID() : "unknown");
340 return false;
341 }
342
343 if (pAddonWindow->GetID() == CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())
344 return true;
345
346 if (pAddonWindow->m_oldWindowId != pAddonWindow->m_windowId &&
347 pAddonWindow->m_windowId != CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())
348 pAddonWindow->m_oldWindowId = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
349
350 Interface_GUIGeneral::lock();
351 if (pAddonWindow->IsDialog())
352 dynamic_cast<CGUIAddonWindowDialog*>(pAddonWindow)->Show(true, true);
353 else
354 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(pAddonWindow->GetID());
355 Interface_GUIGeneral::unlock();
356
357 return true;
358 }
359 //@}
360
361 /*!
362 * Window control functions
363 */
364 //@{
set_focus_id(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)365 bool Interface_GUIWindow::set_focus_id(KODI_HANDLE kodiBase,
366 KODI_GUI_WINDOW_HANDLE handle,
367 int control_id)
368 {
369 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
370 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
371 if (!addon || !pAddonWindow)
372 {
373 CLog::Log(LOGERROR,
374 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
375 "addon '{}'",
376 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
377 return false;
378 }
379
380 if (!pAddonWindow->GetControl(control_id))
381 {
382 CLog::Log(LOGERROR, "Interface_GUIWindow - {}: {} - Control does not exist in window", __func__,
383 addon->Name());
384 return false;
385 }
386
387 Interface_GUIGeneral::lock();
388 CGUIMessage msg(GUI_MSG_SETFOCUS, pAddonWindow->m_windowId, control_id);
389 pAddonWindow->OnMessage(msg);
390 Interface_GUIGeneral::unlock();
391
392 return true;
393 }
394
get_focus_id(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)395 int Interface_GUIWindow::get_focus_id(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
396 {
397 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
398 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
399 if (!addon || !pAddonWindow)
400 {
401 CLog::Log(LOGERROR,
402 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
403 "addon '{}'",
404 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
405 return -1;
406 }
407
408 Interface_GUIGeneral::lock();
409 int control_id = pAddonWindow->GetFocusedControlID();
410 Interface_GUIGeneral::unlock();
411
412 if (control_id == -1)
413 CLog::Log(LOGERROR, "Interface_GUIWindow - {}: {} - No control in this window has focus",
414 __func__, addon->Name());
415
416 return control_id;
417 }
418
set_control_label(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id,const char * label)419 void Interface_GUIWindow::set_control_label(KODI_HANDLE kodiBase,
420 KODI_GUI_WINDOW_HANDLE handle,
421 int control_id,
422 const char* label)
423 {
424 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
425 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
426 if (!addon || !pAddonWindow || !label)
427 {
428 CLog::Log(LOGERROR,
429 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
430 "label='{}') on addon '{}'",
431 __func__, kodiBase, handle, static_cast<const void*>(label),
432 addon ? addon->ID() : "unknown");
433 return;
434 }
435
436 Interface_GUIGeneral::lock();
437 CGUIMessage msg(GUI_MSG_LABEL_SET, pAddonWindow->m_windowId, control_id);
438 msg.SetLabel(label);
439 pAddonWindow->OnMessage(msg);
440 Interface_GUIGeneral::unlock();
441 }
442
set_control_visible(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id,bool visible)443 void Interface_GUIWindow::set_control_visible(KODI_HANDLE kodiBase,
444 KODI_GUI_WINDOW_HANDLE handle,
445 int control_id,
446 bool visible)
447 {
448 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
449 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
450 if (!addon || !pAddonWindow)
451 {
452 CLog::Log(LOGERROR,
453 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
454 "addon '{}'",
455 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
456 return;
457 }
458
459 Interface_GUIGeneral::lock();
460 CGUIMessage msg(visible ? GUI_MSG_VISIBLE : GUI_MSG_HIDDEN, pAddonWindow->m_windowId, control_id);
461 pAddonWindow->OnMessage(msg);
462 Interface_GUIGeneral::unlock();
463 }
464
set_control_selected(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id,bool selected)465 void Interface_GUIWindow::set_control_selected(KODI_HANDLE kodiBase,
466 KODI_GUI_WINDOW_HANDLE handle,
467 int control_id,
468 bool selected)
469 {
470 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
471 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
472 if (!addon || !pAddonWindow)
473 {
474 CLog::Log(LOGERROR,
475 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
476 "addon '{}'",
477 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
478 return;
479 }
480
481 Interface_GUIGeneral::lock();
482 CGUIMessage msg(selected ? GUI_MSG_SET_SELECTED : GUI_MSG_SET_DESELECTED,
483 pAddonWindow->m_windowId, control_id);
484 pAddonWindow->OnMessage(msg);
485 Interface_GUIGeneral::unlock();
486 }
487 //@}
488
489 /*!
490 * Window property functions
491 */
492 //@{
set_property(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key,const char * value)493 void Interface_GUIWindow::set_property(KODI_HANDLE kodiBase,
494 KODI_GUI_WINDOW_HANDLE handle,
495 const char* key,
496 const char* value)
497 {
498 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
499 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
500 if (!addon || !pAddonWindow || !key || !value)
501 {
502 CLog::Log(LOGERROR,
503 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
504 "key='{}', value='{}') on addon '{}'",
505 __func__, kodiBase, handle, static_cast<const void*>(key),
506 static_cast<const void*>(value), addon ? addon->ID() : "unknown");
507 return;
508 }
509
510 std::string lowerKey = key;
511 StringUtils::ToLower(lowerKey);
512
513 Interface_GUIGeneral::lock();
514 pAddonWindow->SetProperty(lowerKey, value);
515 Interface_GUIGeneral::unlock();
516 }
517
set_property_int(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key,int value)518 void Interface_GUIWindow::set_property_int(KODI_HANDLE kodiBase,
519 KODI_GUI_WINDOW_HANDLE handle,
520 const char* key,
521 int value)
522 {
523 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
524 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
525 if (!addon || !pAddonWindow || !key)
526 {
527 CLog::Log(LOGERROR,
528 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
529 "key='{}') on addon '{}'",
530 __func__, kodiBase, handle, static_cast<const void*>(key),
531 addon ? addon->ID() : "unknown");
532 return;
533 }
534
535 std::string lowerKey = key;
536 StringUtils::ToLower(lowerKey);
537
538 Interface_GUIGeneral::lock();
539 pAddonWindow->SetProperty(lowerKey, value);
540 Interface_GUIGeneral::unlock();
541 }
542
set_property_bool(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key,bool value)543 void Interface_GUIWindow::set_property_bool(KODI_HANDLE kodiBase,
544 KODI_GUI_WINDOW_HANDLE handle,
545 const char* key,
546 bool value)
547 {
548 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
549 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
550 if (!addon || !pAddonWindow || !key)
551 {
552 CLog::Log(LOGERROR,
553 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
554 "key='{}') on addon '{}'",
555 __func__, kodiBase, handle, static_cast<const void*>(key),
556 addon ? addon->ID() : "unknown");
557 return;
558 }
559
560 std::string lowerKey = key;
561 StringUtils::ToLower(lowerKey);
562
563 Interface_GUIGeneral::lock();
564 pAddonWindow->SetProperty(lowerKey, value);
565 Interface_GUIGeneral::unlock();
566 }
567
set_property_double(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key,double value)568 void Interface_GUIWindow::set_property_double(KODI_HANDLE kodiBase,
569 KODI_GUI_WINDOW_HANDLE handle,
570 const char* key,
571 double value)
572 {
573 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
574 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
575 if (!addon || !pAddonWindow || !key)
576 {
577 CLog::Log(LOGERROR,
578 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
579 "key='{}') on addon '{}'",
580 __func__, kodiBase, handle, static_cast<const void*>(key),
581 addon ? addon->ID() : "unknown");
582 return;
583 }
584
585 std::string lowerKey = key;
586 StringUtils::ToLower(lowerKey);
587
588 Interface_GUIGeneral::lock();
589 pAddonWindow->SetProperty(lowerKey, value);
590 Interface_GUIGeneral::unlock();
591 }
592
get_property(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key)593 char* Interface_GUIWindow::get_property(KODI_HANDLE kodiBase,
594 KODI_GUI_WINDOW_HANDLE handle,
595 const char* key)
596 {
597 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
598 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
599 if (!addon || !pAddonWindow || !key)
600 {
601 CLog::Log(LOGERROR,
602 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
603 "key='{}') on addon '{}'",
604 __func__, kodiBase, handle, static_cast<const void*>(key),
605 addon ? addon->ID() : "unknown");
606 return nullptr;
607 }
608
609 std::string lowerKey = key;
610 StringUtils::ToLower(lowerKey);
611
612 Interface_GUIGeneral::lock();
613 std::string value = pAddonWindow->GetProperty(lowerKey).asString();
614 Interface_GUIGeneral::unlock();
615
616 return strdup(value.c_str());
617 }
618
get_property_int(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key)619 int Interface_GUIWindow::get_property_int(KODI_HANDLE kodiBase,
620 KODI_GUI_WINDOW_HANDLE handle,
621 const char* key)
622 {
623 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
624 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
625 if (!addon || !pAddonWindow || !key)
626 {
627 CLog::Log(LOGERROR,
628 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
629 "key='{}') on addon '{}'",
630 __func__, kodiBase, handle, static_cast<const void*>(key),
631 addon ? addon->ID() : "unknown");
632 return -1;
633 }
634
635 std::string lowerKey = key;
636 StringUtils::ToLower(lowerKey);
637
638 Interface_GUIGeneral::lock();
639 int value = static_cast<int>(pAddonWindow->GetProperty(lowerKey).asInteger());
640 Interface_GUIGeneral::unlock();
641
642 return value;
643 }
644
get_property_bool(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key)645 bool Interface_GUIWindow::get_property_bool(KODI_HANDLE kodiBase,
646 KODI_GUI_WINDOW_HANDLE handle,
647 const char* key)
648 {
649 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
650 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
651 if (!addon || !pAddonWindow || !key)
652 {
653 CLog::Log(LOGERROR,
654 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
655 "key='{}') on addon '{}'",
656 __func__, kodiBase, handle, static_cast<const void*>(key),
657 addon ? addon->ID() : "unknown");
658 return false;
659 }
660
661 std::string lowerKey = key;
662 StringUtils::ToLower(lowerKey);
663
664 Interface_GUIGeneral::lock();
665 bool value = pAddonWindow->GetProperty(lowerKey).asBoolean();
666 Interface_GUIGeneral::unlock();
667
668 return value;
669 }
670
get_property_double(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key)671 double Interface_GUIWindow::get_property_double(KODI_HANDLE kodiBase,
672 KODI_GUI_WINDOW_HANDLE handle,
673 const char* key)
674 {
675 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
676 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
677 if (!addon || !pAddonWindow || !key)
678 {
679 CLog::Log(LOGERROR,
680 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
681 "key='{}') on addon '{}'",
682 __func__, kodiBase, handle, static_cast<const void*>(key),
683 addon ? addon->ID() : "unknown");
684 return 0.0;
685 }
686
687 std::string lowerKey = key;
688 StringUtils::ToLower(lowerKey);
689
690 Interface_GUIGeneral::lock();
691 double value = pAddonWindow->GetProperty(lowerKey).asDouble();
692 Interface_GUIGeneral::unlock();
693
694 return value;
695 }
696
clear_properties(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)697 void Interface_GUIWindow::clear_properties(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
698 {
699 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
700 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
701 if (!addon || !pAddonWindow)
702 {
703 CLog::Log(LOGERROR,
704 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
705 "addon '{}'",
706 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
707 return;
708 }
709
710 Interface_GUIGeneral::lock();
711 pAddonWindow->ClearProperties();
712 Interface_GUIGeneral::unlock();
713 }
714
clear_property(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key)715 void Interface_GUIWindow::clear_property(KODI_HANDLE kodiBase,
716 KODI_GUI_WINDOW_HANDLE handle,
717 const char* key)
718 {
719 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
720 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
721 if (!addon || !pAddonWindow || !key)
722 {
723 CLog::Log(LOGERROR,
724 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
725 "key='{}') on addon '{}'",
726 __func__, kodiBase, handle, static_cast<const void*>(key),
727 addon ? addon->ID() : "unknown");
728 return;
729 }
730
731 std::string lowerKey = key;
732 StringUtils::ToLower(lowerKey);
733
734 Interface_GUIGeneral::lock();
735 pAddonWindow->SetProperty(lowerKey, "");
736 Interface_GUIGeneral::unlock();
737 }
738 //@}
739
740 /*!
741 * List item functions
742 */
743 //@{
clear_item_list(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)744 void Interface_GUIWindow::clear_item_list(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
745 {
746 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
747 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
748 if (!addon || !pAddonWindow)
749 {
750 CLog::Log(LOGERROR,
751 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
752 "addon '{}'",
753 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
754 return;
755 }
756
757 Interface_GUIGeneral::lock();
758 pAddonWindow->ClearList();
759 Interface_GUIGeneral::unlock();
760 }
761
add_list_item(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,KODI_GUI_LISTITEM_HANDLE item,int list_position)762 void Interface_GUIWindow::add_list_item(KODI_HANDLE kodiBase,
763 KODI_GUI_WINDOW_HANDLE handle,
764 KODI_GUI_LISTITEM_HANDLE item,
765 int list_position)
766 {
767 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
768 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
769 if (!addon || !pAddonWindow || !item)
770 {
771 CLog::Log(LOGERROR,
772 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
773 "item='{}') on addon '{}'",
774 __func__, kodiBase, handle, item, addon ? addon->ID() : "unknown");
775 return;
776 }
777
778 CFileItemPtr* pItem(static_cast<CFileItemPtr*>(item));
779 if (pItem->get() == nullptr)
780 {
781 CLog::Log(LOGERROR, "Interface_GUIWindow::{} - empty list item called on addon '{}'", __func__,
782 addon->ID());
783 return;
784 }
785
786 Interface_GUIGeneral::lock();
787 pAddonWindow->AddItem(pItem, list_position);
788 Interface_GUIGeneral::unlock();
789 }
790
remove_list_item_from_position(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int list_position)791 void Interface_GUIWindow::remove_list_item_from_position(KODI_HANDLE kodiBase,
792 KODI_GUI_WINDOW_HANDLE handle,
793 int list_position)
794 {
795 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
796 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
797 if (!addon || !pAddonWindow)
798 {
799 CLog::Log(LOGERROR,
800 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
801 "addon '{}'",
802 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
803 return;
804 }
805
806 Interface_GUIGeneral::lock();
807 pAddonWindow->RemoveItem(list_position);
808 Interface_GUIGeneral::unlock();
809 }
810
remove_list_item(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,KODI_GUI_LISTITEM_HANDLE item)811 void Interface_GUIWindow::remove_list_item(KODI_HANDLE kodiBase,
812 KODI_GUI_WINDOW_HANDLE handle,
813 KODI_GUI_LISTITEM_HANDLE item)
814 {
815 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
816 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
817 if (!addon || !pAddonWindow || !item)
818 {
819 CLog::Log(LOGERROR,
820 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
821 "item='{}') on addon '{}'",
822 __func__, kodiBase, handle, item, addon ? addon->ID() : "unknown");
823 return;
824 }
825
826 CFileItemPtr* pItem(static_cast<CFileItemPtr*>(item));
827 if (pItem->get() == nullptr)
828 {
829 CLog::Log(LOGERROR, "Interface_GUIWindow::{} - empty list item called on addon '{}'", __func__,
830 addon->ID());
831 return;
832 }
833
834 Interface_GUIGeneral::lock();
835 pAddonWindow->RemoveItem(pItem);
836 Interface_GUIGeneral::unlock();
837 }
838
get_list_item(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int list_position)839 KODI_GUI_LISTITEM_HANDLE Interface_GUIWindow::get_list_item(KODI_HANDLE kodiBase,
840 KODI_GUI_WINDOW_HANDLE handle,
841 int list_position)
842 {
843 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
844 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
845 if (!addon || !pAddonWindow)
846 {
847 CLog::Log(LOGERROR,
848 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
849 "addon '{}'",
850 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
851 return nullptr;
852 }
853
854 Interface_GUIGeneral::lock();
855 CFileItemPtr* pItem(pAddonWindow->GetListItem(list_position));
856 if (pItem == nullptr || pItem->get() == nullptr)
857 {
858 CLog::Log(LOGERROR, "ADDON::Interface_GUIWindow - {}: {} - Index out of range", __func__,
859 addon->Name());
860
861 if (pItem)
862 {
863 delete pItem;
864 pItem = nullptr;
865 }
866 }
867 Interface_GUIGeneral::unlock();
868
869 return pItem;
870 }
871
set_current_list_position(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int list_position)872 void Interface_GUIWindow::set_current_list_position(KODI_HANDLE kodiBase,
873 KODI_GUI_WINDOW_HANDLE handle,
874 int list_position)
875 {
876 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
877 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
878 if (!addon || !pAddonWindow)
879 {
880 CLog::Log(LOGERROR,
881 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
882 "addon '{}'",
883 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
884 return;
885 }
886
887 Interface_GUIGeneral::lock();
888 pAddonWindow->SetCurrentListPosition(list_position);
889 Interface_GUIGeneral::unlock();
890 }
891
get_current_list_position(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)892 int Interface_GUIWindow::get_current_list_position(KODI_HANDLE kodiBase,
893 KODI_GUI_WINDOW_HANDLE handle)
894 {
895 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
896 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
897 if (!addon || !pAddonWindow)
898 {
899 CLog::Log(LOGERROR,
900 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
901 "addon '{}'",
902 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
903 return -1;
904 }
905
906 Interface_GUIGeneral::lock();
907 int listPos = pAddonWindow->GetCurrentListPosition();
908 Interface_GUIGeneral::unlock();
909
910 return listPos;
911 }
912
get_list_size(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)913 int Interface_GUIWindow::get_list_size(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
914 {
915 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
916 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
917 if (!addon || !pAddonWindow)
918 {
919 CLog::Log(LOGERROR,
920 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
921 "addon '{}'",
922 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
923 return -1;
924 }
925
926 Interface_GUIGeneral::lock();
927 int listSize = pAddonWindow->GetListSize();
928 Interface_GUIGeneral::unlock();
929
930 return listSize;
931 }
932
set_container_property(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * key,const char * value)933 void Interface_GUIWindow::set_container_property(KODI_HANDLE kodiBase,
934 KODI_GUI_WINDOW_HANDLE handle,
935 const char* key,
936 const char* value)
937 {
938 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
939 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
940 if (!addon || !pAddonWindow || !key || !value)
941 {
942 CLog::Log(LOGERROR,
943 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
944 "key='{}', value='{}') on addon '{}'",
945 __func__, kodiBase, handle, static_cast<const void*>(key),
946 static_cast<const void*>(value), addon ? addon->ID() : "unknown");
947 return;
948 }
949
950 Interface_GUIGeneral::lock();
951 pAddonWindow->SetContainerProperty(key, value);
952 Interface_GUIGeneral::unlock();
953 }
954
set_container_content(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,const char * value)955 void Interface_GUIWindow::set_container_content(KODI_HANDLE kodiBase,
956 KODI_GUI_WINDOW_HANDLE handle,
957 const char* value)
958 {
959 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
960 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
961 if (!addon || !pAddonWindow || !value)
962 {
963 CLog::Log(LOGERROR,
964 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}', "
965 "value='{}') on addon '{}'",
966 __func__, kodiBase, handle, static_cast<const void*>(value),
967 addon ? addon->ID() : "unknown");
968 return;
969 }
970
971 Interface_GUIGeneral::lock();
972 pAddonWindow->SetContainerContent(value);
973 Interface_GUIGeneral::unlock();
974 }
975
get_current_container_id(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)976 int Interface_GUIWindow::get_current_container_id(KODI_HANDLE kodiBase,
977 KODI_GUI_WINDOW_HANDLE handle)
978 {
979 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
980 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
981 if (!addon || !pAddonWindow)
982 {
983 CLog::Log(LOGERROR,
984 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
985 "addon '{}'",
986 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
987 return -1;
988 }
989
990 Interface_GUIGeneral::lock();
991 int id = pAddonWindow->GetCurrentContainerControlId();
992 Interface_GUIGeneral::unlock();
993
994 return id;
995 }
996 //@}
997
998 /*!
999 * Various functions
1000 */
1001 //@{
mark_dirty_region(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle)1002 void Interface_GUIWindow::mark_dirty_region(KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle)
1003 {
1004 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
1005 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
1006 if (!addon || !pAddonWindow)
1007 {
1008 CLog::Log(LOGERROR,
1009 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
1010 "addon '{}'",
1011 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
1012 return;
1013 }
1014
1015 Interface_GUIGeneral::lock();
1016 pAddonWindow->MarkDirtyRegion();
1017 Interface_GUIGeneral::unlock();
1018 }
1019 //@}
1020
1021 /*!
1022 * GUI control access functions
1023 */
1024 //@{
get_control_button(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1025 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_button(KODI_HANDLE kodiBase,
1026 KODI_GUI_WINDOW_HANDLE handle,
1027 int control_id)
1028 {
1029 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_BUTTON,
1030 "button");
1031 }
1032
get_control_edit(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1033 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_edit(KODI_HANDLE kodiBase,
1034 KODI_GUI_WINDOW_HANDLE handle,
1035 int control_id)
1036 {
1037 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_EDIT, "edit");
1038 }
1039
get_control_fade_label(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1040 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_fade_label(KODI_HANDLE kodiBase,
1041 KODI_GUI_WINDOW_HANDLE handle,
1042 int control_id)
1043 {
1044 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_FADELABEL,
1045 "fade label");
1046 }
1047
get_control_image(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1048 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_image(KODI_HANDLE kodiBase,
1049 KODI_GUI_WINDOW_HANDLE handle,
1050 int control_id)
1051 {
1052 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_IMAGE, "image");
1053 }
1054
get_control_label(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1055 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_label(KODI_HANDLE kodiBase,
1056 KODI_GUI_WINDOW_HANDLE handle,
1057 int control_id)
1058 {
1059 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_LABEL, "label");
1060 }
get_control_progress(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1061 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_progress(KODI_HANDLE kodiBase,
1062 KODI_GUI_WINDOW_HANDLE handle,
1063 int control_id)
1064 {
1065 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_PROGRESS,
1066 "progress");
1067 }
1068
get_control_radio_button(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1069 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_radio_button(KODI_HANDLE kodiBase,
1070 KODI_GUI_WINDOW_HANDLE handle,
1071 int control_id)
1072 {
1073 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_RADIO,
1074 "radio button");
1075 }
1076
get_control_render_addon(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1077 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_render_addon(KODI_HANDLE kodiBase,
1078 KODI_GUI_WINDOW_HANDLE handle,
1079 int control_id)
1080 {
1081 CGUIControl* pGUIControl = static_cast<CGUIControl*>(GetControl(
1082 kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_RENDERADDON, "renderaddon"));
1083 if (!pGUIControl)
1084 return nullptr;
1085
1086 CGUIAddonRenderingControl* pRenderControl =
1087 new CGUIAddonRenderingControl(dynamic_cast<CGUIRenderingControl*>(pGUIControl));
1088 return pRenderControl;
1089 }
1090
get_control_settings_slider(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1091 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_settings_slider(
1092 KODI_HANDLE kodiBase, KODI_GUI_WINDOW_HANDLE handle, int control_id)
1093 {
1094 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SETTINGS_SLIDER,
1095 "settings slider");
1096 }
1097
get_control_slider(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1098 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_slider(KODI_HANDLE kodiBase,
1099 KODI_GUI_WINDOW_HANDLE handle,
1100 int control_id)
1101 {
1102 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SLIDER,
1103 "slider");
1104 }
1105
get_control_spin(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1106 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_spin(KODI_HANDLE kodiBase,
1107 KODI_GUI_WINDOW_HANDLE handle,
1108 int control_id)
1109 {
1110 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_SPINEX, "spin");
1111 }
1112
get_control_text_box(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id)1113 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::get_control_text_box(KODI_HANDLE kodiBase,
1114 KODI_GUI_WINDOW_HANDLE handle,
1115 int control_id)
1116 {
1117 return GetControl(kodiBase, handle, control_id, __func__, CGUIControl::GUICONTROL_TEXTBOX,
1118 "textbox");
1119 }
1120 //@}
1121
GetControl(KODI_HANDLE kodiBase,KODI_GUI_WINDOW_HANDLE handle,int control_id,const char * function,CGUIControl::GUICONTROLTYPES type,const std::string & typeName)1122 KODI_GUI_CONTROL_HANDLE Interface_GUIWindow::GetControl(KODI_HANDLE kodiBase,
1123 KODI_GUI_WINDOW_HANDLE handle,
1124 int control_id,
1125 const char* function,
1126 CGUIControl::GUICONTROLTYPES type,
1127 const std::string& typeName)
1128 {
1129 CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
1130 CGUIAddonWindow* pAddonWindow = static_cast<CGUIAddonWindow*>(handle);
1131 if (!addon || !pAddonWindow)
1132 {
1133 CLog::Log(LOGERROR,
1134 "Interface_GUIWindow::{} - invalid handler data (kodiBase='{}', handle='{}') on "
1135 "addon '{}'",
1136 __func__, kodiBase, handle, addon ? addon->ID() : "unknown");
1137 return nullptr;
1138 }
1139
1140 return pAddonWindow->GetAddonControl(control_id, type, typeName);
1141 }
1142
GetNextAvailableWindowId()1143 int Interface_GUIWindow::GetNextAvailableWindowId()
1144 {
1145 Interface_GUIGeneral::lock();
1146
1147 // if window WINDOW_ADDON_END is in use it means addon can't create more windows
1148 if (CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_ADDON_END))
1149 {
1150 Interface_GUIGeneral::unlock();
1151 CLog::Log(LOGERROR,
1152 "Interface_GUIWindow::{} - Maximum number of windows for binary addons reached",
1153 __func__);
1154 return -1;
1155 }
1156
1157 // window id's WINDOW_ADDON_START - WINDOW_ADDON_END are reserved for addons
1158 // get first window id that is not in use
1159 int id = WINDOW_ADDON_START;
1160 while (id < WINDOW_ADDON_END &&
1161 CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id) != nullptr)
1162 id++;
1163
1164 Interface_GUIGeneral::unlock();
1165 return id;
1166 }
1167
CGUIAddonWindow(int id,const std::string & strXML,CAddonDll * addon,bool isMedia)1168 CGUIAddonWindow::CGUIAddonWindow(int id, const std::string& strXML, CAddonDll* addon, bool isMedia)
1169 : CGUIMediaWindow(id, strXML.c_str()),
1170 m_clientHandle{nullptr},
1171 CBOnInit{nullptr},
1172 CBOnFocus{nullptr},
1173 CBOnClick{nullptr},
1174 CBOnAction{nullptr},
1175 CBGetContextButtons{nullptr},
1176 CBOnContextButton{nullptr},
1177 m_windowId(id),
1178 m_oldWindowId(0),
1179 m_actionEvent(true),
1180 m_addon(addon),
1181 m_isMedia(isMedia)
1182 {
1183 m_loadType = LOAD_ON_GUI_INIT;
1184 }
1185
GetAddonControl(int controlId,CGUIControl::GUICONTROLTYPES type,const std::string & typeName)1186 CGUIControl* CGUIAddonWindow::GetAddonControl(int controlId,
1187 CGUIControl::GUICONTROLTYPES type,
1188 const std::string& typeName)
1189 {
1190 // Load window resources, if not already done, to have related xml content
1191 // present and to let control find it
1192 if (!m_windowLoaded)
1193 {
1194 if (!Initialize())
1195 {
1196 CLog::Log(LOGERROR,
1197 "CGUIAddonGUI_Window::{}: {} - Window initialize failed by control id '{}' request "
1198 "for '{}'",
1199 __func__, m_addon->Name(), controlId, typeName);
1200 return nullptr;
1201 }
1202 }
1203
1204 CGUIControl* pGUIControl = GetControl(controlId);
1205 if (!pGUIControl)
1206 {
1207 CLog::Log(LOGERROR,
1208 "CGUIAddonGUI_Window::{}: {} - Requested GUI control Id '{}' for '{}' not present!",
1209 __func__, m_addon->Name(), controlId, typeName);
1210 return nullptr;
1211 }
1212 else if (pGUIControl->GetControlType() != type)
1213 {
1214 CLog::Log(LOGERROR,
1215 "CGUIAddonGUI_Window::{}: {} - Requested GUI control Id '{}' not the type '{}'!",
1216 __func__, m_addon->Name(), controlId, typeName);
1217 return nullptr;
1218 }
1219
1220 return pGUIControl;
1221 }
1222
OnAction(const CAction & action)1223 bool CGUIAddonWindow::OnAction(const CAction& action)
1224 {
1225 // Let addon decide whether it wants to handle action first
1226 if (CBOnAction &&
1227 CBOnAction(m_clientHandle, CAddonGUITranslator::TranslateActionIdToAddon(action.GetID())))
1228 return true;
1229
1230 return CGUIWindow::OnAction(action);
1231 }
1232
OnMessage(CGUIMessage & message)1233 bool CGUIAddonWindow::OnMessage(CGUIMessage& message)
1234 {
1235 switch (message.GetMessage())
1236 {
1237 case GUI_MSG_WINDOW_DEINIT:
1238 {
1239 return CGUIMediaWindow::OnMessage(message);
1240 }
1241 break;
1242
1243 case GUI_MSG_WINDOW_INIT:
1244 {
1245 CGUIMediaWindow::OnMessage(message);
1246
1247 if (CBOnInit)
1248 CBOnInit(m_clientHandle);
1249 return true;
1250 }
1251 break;
1252
1253 case GUI_MSG_FOCUSED:
1254 {
1255 if (m_viewControl.HasControl(message.GetControlId()) &&
1256 m_viewControl.GetCurrentControl() != message.GetControlId())
1257 {
1258 m_viewControl.SetFocused();
1259 return true;
1260 }
1261 // check if our focused control is one of our category buttons
1262 int iControl = message.GetControlId();
1263 if (CBOnFocus)
1264 CBOnFocus(m_clientHandle, iControl);
1265 }
1266 break;
1267
1268 case GUI_MSG_NOTIFY_ALL:
1269 {
1270 // most messages from GUI_MSG_NOTIFY_ALL break container content, whitelist working ones.
1271 if (message.GetParam1() == GUI_MSG_PAGE_CHANGE ||
1272 message.GetParam1() == GUI_MSG_WINDOW_RESIZE)
1273 return CGUIMediaWindow::OnMessage(message);
1274 return true;
1275 }
1276
1277 case GUI_MSG_CLICKED:
1278 {
1279 int iControl = message.GetSenderId();
1280 if (iControl && iControl != this->GetID())
1281 {
1282 CGUIControl* controlClicked = this->GetControl(iControl);
1283
1284 // The old python way used to check list AND SELECITEM method or if its a button, checkmark.
1285 // Its done this way for now to allow other controls without a python version like togglebutton to still raise a onAction event
1286 if (controlClicked) // Will get problems if we the id is not on the window and we try to do GetControlType on it. So check to make sure it exists
1287 {
1288 if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM ||
1289 message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) ||
1290 !controlClicked->IsContainer())
1291 {
1292 if (CBOnClick)
1293 return CBOnClick(m_clientHandle, iControl);
1294 }
1295 else if (controlClicked->IsContainer() &&
1296 (message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK ||
1297 message.GetParam1() == ACTION_CONTEXT_MENU))
1298 {
1299 if (CBOnAction)
1300 {
1301 // Check addon want to handle right click for a context menu, if
1302 // not used from addon becomes "GetContextButtons(...)" called.
1303 if (CBOnAction(m_clientHandle, ADDON_ACTION_CONTEXT_MENU))
1304 return true;
1305 }
1306 }
1307 }
1308 }
1309 }
1310 break;
1311 }
1312
1313 return CGUIMediaWindow::OnMessage(message);
1314 }
1315
AllocResources(bool forceLoad)1316 void CGUIAddonWindow::AllocResources(bool forceLoad /*= false */)
1317 {
1318 std::string tmpDir = URIUtils::GetDirectory(GetProperty("xmlfile").asString());
1319 std::string fallbackMediaPath;
1320 URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
1321 URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
1322 m_mediaDir = fallbackMediaPath;
1323
1324 CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir);
1325 CGUIMediaWindow::AllocResources(forceLoad);
1326 CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir);
1327 }
1328
Render()1329 void CGUIAddonWindow::Render()
1330 {
1331 CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir);
1332 CGUIMediaWindow::Render();
1333 CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir);
1334 }
1335
AddItem(CFileItemPtr * fileItem,int itemPosition)1336 void CGUIAddonWindow::AddItem(CFileItemPtr* fileItem, int itemPosition)
1337 {
1338 if (itemPosition == -1 || itemPosition > m_vecItems->Size())
1339 {
1340 m_vecItems->Add(*fileItem);
1341 }
1342 else if (itemPosition < -1 && !(itemPosition - 1 < m_vecItems->Size()))
1343 {
1344 m_vecItems->AddFront(*fileItem, 0);
1345 }
1346 else
1347 {
1348 m_vecItems->AddFront(*fileItem, itemPosition);
1349 }
1350 m_viewControl.SetItems(*m_vecItems);
1351 UpdateButtons();
1352 }
1353
RemoveItem(int itemPosition)1354 void CGUIAddonWindow::RemoveItem(int itemPosition)
1355 {
1356 m_vecItems->Remove(itemPosition);
1357 m_viewControl.SetItems(*m_vecItems);
1358 UpdateButtons();
1359 }
1360
RemoveItem(CFileItemPtr * fileItem)1361 void CGUIAddonWindow::RemoveItem(CFileItemPtr* fileItem)
1362 {
1363 m_vecItems->Remove(fileItem->get());
1364 m_viewControl.SetItems(*m_vecItems);
1365 UpdateButtons();
1366 }
1367
GetCurrentListPosition()1368 int CGUIAddonWindow::GetCurrentListPosition()
1369 {
1370 return m_viewControl.GetSelectedItem();
1371 }
1372
SetCurrentListPosition(int item)1373 void CGUIAddonWindow::SetCurrentListPosition(int item)
1374 {
1375 m_viewControl.SetSelectedItem(item);
1376 }
1377
GetListSize()1378 int CGUIAddonWindow::GetListSize()
1379 {
1380 return m_vecItems->Size();
1381 }
1382
GetListItem(int position)1383 CFileItemPtr* CGUIAddonWindow::GetListItem(int position)
1384 {
1385 if (position < 0 || position >= m_vecItems->Size())
1386 return nullptr;
1387 return new CFileItemPtr(m_vecItems->Get(position));
1388 }
1389
ClearList()1390 void CGUIAddonWindow::ClearList()
1391 {
1392 ClearFileItems();
1393
1394 m_viewControl.SetItems(*m_vecItems);
1395 UpdateButtons();
1396 }
1397
SetContainerProperty(const std::string & key,const std::string & value)1398 void CGUIAddonWindow::SetContainerProperty(const std::string& key, const std::string& value)
1399 {
1400 m_vecItems->SetProperty(key, value);
1401 }
1402
SetContainerContent(const std::string & value)1403 void CGUIAddonWindow::SetContainerContent(const std::string& value)
1404 {
1405 m_vecItems->SetContent(value);
1406 }
1407
GetCurrentContainerControlId()1408 int CGUIAddonWindow::GetCurrentContainerControlId()
1409 {
1410 return m_viewControl.GetCurrentControl();
1411 }
1412
GetContextButtons(int itemNumber,CContextButtons & buttons)1413 void CGUIAddonWindow::GetContextButtons(int itemNumber, CContextButtons& buttons)
1414 {
1415 gui_context_menu_pair c_buttons[ADDON_MAX_CONTEXT_ENTRIES] = {{0}};
1416 unsigned int size = ADDON_MAX_CONTEXT_ENTRIES;
1417 if (CBGetContextButtons)
1418 {
1419 CBGetContextButtons(m_clientHandle, itemNumber, c_buttons, &size);
1420 for (unsigned int i = 0; i < size; ++i)
1421 buttons.push_back(std::pair<unsigned int, std::string>(c_buttons[i].id, c_buttons[i].name));
1422 }
1423 }
1424
OnContextButton(int itemNumber,CONTEXT_BUTTON button)1425 bool CGUIAddonWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1426 {
1427 if (CBOnContextButton)
1428 return CBOnContextButton(m_clientHandle, itemNumber, static_cast<unsigned int>(button));
1429 return false;
1430 }
1431
WaitForActionEvent(unsigned int timeout)1432 void CGUIAddonWindow::WaitForActionEvent(unsigned int timeout)
1433 {
1434 m_actionEvent.WaitMSec(timeout);
1435 m_actionEvent.Reset();
1436 }
1437
PulseActionEvent()1438 void CGUIAddonWindow::PulseActionEvent()
1439 {
1440 m_actionEvent.Set();
1441 }
1442
SetupShares()1443 void CGUIAddonWindow::SetupShares()
1444 {
1445 UpdateButtons();
1446 }
1447
1448
CGUIAddonWindowDialog(int id,const std::string & strXML,CAddonDll * addon)1449 CGUIAddonWindowDialog::CGUIAddonWindowDialog(int id, const std::string& strXML, CAddonDll* addon)
1450 : CGUIAddonWindow(id, strXML, addon, false), m_bRunning(false)
1451 {
1452 }
1453
Show(bool show,bool modal)1454 void CGUIAddonWindowDialog::Show(bool show /* = true */, bool modal /* = true*/)
1455 {
1456 if (modal)
1457 {
1458 unsigned int count = CServiceBroker::GetWinSystem()->GetGfxContext().exit();
1459 CApplicationMessenger::GetInstance().SendMsg(TMSG_GUI_ADDON_DIALOG, 0, show ? 1 : 0,
1460 static_cast<void*>(this));
1461 CServiceBroker::GetWinSystem()->GetGfxContext().restore(count);
1462 }
1463 else
1464 CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ADDON_DIALOG, 0, show ? 1 : 0,
1465 static_cast<void*>(this));
1466 }
1467
Show_Internal(bool show)1468 void CGUIAddonWindowDialog::Show_Internal(bool show /* = true */)
1469 {
1470 if (show)
1471 {
1472 m_bRunning = true;
1473 CServiceBroker::GetGUI()->GetWindowManager().RegisterDialog(this);
1474
1475 // activate this window...
1476 CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, GetID());
1477 OnMessage(msg);
1478
1479 // this dialog is derived from GUIMediaWindow
1480 // make sure it is rendered last
1481 m_renderOrder = RENDER_ORDER_DIALOG;
1482 while (m_bRunning)
1483 {
1484 if (!ProcessRenderLoop(false))
1485 break;
1486 }
1487 }
1488 else // hide
1489 {
1490 m_bRunning = false;
1491
1492 CGUIMessage msg(GUI_MSG_WINDOW_DEINIT, 0, 0);
1493 OnMessage(msg);
1494
1495 CServiceBroker::GetGUI()->GetWindowManager().RemoveDialog(GetID());
1496 }
1497 }
1498
1499 } /* namespace ADDON */
1500