[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / windows / GUIWindowPVRBase.cpp
blobc6ef99abcedb8c91958f6320a0e8752cec36abd8
1 /*
2 * Copyright (C) 2012-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.
7 */
9 #include "GUIWindowPVRBase.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIUserMessages.h"
14 #include "ServiceBroker.h"
15 #include "addons/AddonManager.h"
16 #include "addons/addoninfo/AddonType.h"
17 #include "dialogs/GUIDialogExtendedProgressBar.h"
18 #include "dialogs/GUIDialogSelect.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIMessage.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/LocalizeStrings.h"
23 #include "input/actions/Action.h"
24 #include "input/actions/ActionIDs.h"
25 #include "messaging/ApplicationMessenger.h"
26 #include "messaging/helpers/DialogOKHelper.h"
27 #include "pvr/PVRManager.h"
28 #include "pvr/PVRPlaybackState.h"
29 #include "pvr/PVRThumbLoader.h"
30 #include "pvr/addons/PVRClient.h"
31 #include "pvr/addons/PVRClients.h"
32 #include "pvr/channels/PVRChannelGroup.h"
33 #include "pvr/channels/PVRChannelGroups.h"
34 #include "pvr/channels/PVRChannelGroupsContainer.h"
35 #include "pvr/filesystem/PVRGUIDirectory.h"
36 #include "pvr/guilib/PVRGUIActionsChannels.h"
37 #include "utils/Variant.h"
38 #include "utils/log.h"
40 #include <iterator>
41 #include <memory>
42 #include <mutex>
43 #include <string>
44 #include <utility>
45 #include <vector>
47 using namespace std::chrono_literals;
49 #define MAX_INVALIDATION_FREQUENCY 2000ms // limit to one invalidation per X milliseconds
51 using namespace PVR;
52 using namespace KODI::MESSAGING;
54 namespace PVR
57 class CGUIPVRChannelGroupsSelector
59 public:
60 virtual ~CGUIPVRChannelGroupsSelector() = default;
62 bool Initialize(CGUIWindow* parent, bool bRadio);
64 bool HasFocus() const;
65 std::shared_ptr<CPVRChannelGroup> GetSelectedChannelGroup() const;
66 bool SelectChannelGroup(const std::shared_ptr<CPVRChannelGroup>& newGroup);
68 private:
69 CGUIControl* m_control = nullptr;
70 std::vector<std::shared_ptr<CPVRChannelGroup>> m_channelGroups;
73 } // namespace PVR
75 bool CGUIPVRChannelGroupsSelector::Initialize(CGUIWindow* parent, bool bRadio)
77 CGUIControl* control = parent->GetControl(CONTROL_LSTCHANNELGROUPS);
78 if (control && control->IsContainer())
80 m_control = control;
81 m_channelGroups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(bRadio)->GetMembers(true);
83 CFileItemList channelGroupItems;
84 CPVRGUIDirectory::GetChannelGroupsDirectory(bRadio, true, channelGroupItems);
86 CGUIMessage msg(GUI_MSG_LABEL_BIND, m_control->GetID(), CONTROL_LSTCHANNELGROUPS, 0, 0, &channelGroupItems);
87 m_control->OnMessage(msg);
88 return true;
90 return false;
93 bool CGUIPVRChannelGroupsSelector::HasFocus() const
95 return m_control && m_control->HasFocus();
98 std::shared_ptr<CPVRChannelGroup> CGUIPVRChannelGroupsSelector::GetSelectedChannelGroup() const
100 if (m_control)
102 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, m_control->GetID(), CONTROL_LSTCHANNELGROUPS);
103 m_control->OnMessage(msg);
105 const auto it = std::next(m_channelGroups.begin(), msg.GetParam1());
106 if (it != m_channelGroups.end())
108 return *it;
111 return std::shared_ptr<CPVRChannelGroup>();
114 bool CGUIPVRChannelGroupsSelector::SelectChannelGroup(const std::shared_ptr<CPVRChannelGroup>& newGroup)
116 if (m_control && newGroup)
118 int iIndex = 0;
119 for (const auto& group : m_channelGroups)
121 if (*newGroup == *group)
123 CGUIMessage msg(GUI_MSG_ITEM_SELECT, m_control->GetID(), CONTROL_LSTCHANNELGROUPS, iIndex);
124 m_control->OnMessage(msg);
125 return true;
127 ++iIndex;
130 return false;
133 CGUIWindowPVRBase::CGUIWindowPVRBase(bool bRadio, int id, const std::string& xmlFile)
134 : CGUIMediaWindow(id, xmlFile.c_str()),
135 m_bRadio(bRadio),
136 m_channelGroupsSelector(new CGUIPVRChannelGroupsSelector)
138 // prevent removable drives to appear in directory listing (base class default behavior).
139 m_rootDir.AllowNonLocalSources(false);
141 CServiceBroker::GetPVRManager().Events().Subscribe(this, &CGUIWindowPVRBase::Notify);
144 CGUIWindowPVRBase::~CGUIWindowPVRBase()
146 if (m_channelGroup)
147 m_channelGroup->Events().Unsubscribe(this);
149 CServiceBroker::GetPVRManager().Events().Unsubscribe(this);
152 void CGUIWindowPVRBase::UpdateSelectedItemPath()
154 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().SetSelectedChannelPath(
155 m_bRadio, m_viewControl.GetSelectedItemPath());
158 void CGUIWindowPVRBase::Notify(const PVREvent& event)
160 // call virtual event handler function
161 NotifyEvent(event);
164 void CGUIWindowPVRBase::NotifyEvent(const PVREvent& event)
166 if (event == PVREvent::ManagerStopped)
168 ClearData();
170 else if (m_active)
172 if (event == PVREvent::SystemSleep)
174 CGUIMessage m(GUI_MSG_SYSTEM_SLEEP, GetID(), 0, static_cast<int>(event));
175 CServiceBroker::GetAppMessenger()->SendGUIMessage(m);
177 else if (event == PVREvent::SystemWake)
179 CGUIMessage m(GUI_MSG_SYSTEM_WAKE, GetID(), 0, static_cast<int>(event));
180 CServiceBroker::GetAppMessenger()->SendGUIMessage(m);
182 else
184 CGUIMessage m(GUI_MSG_REFRESH_LIST, GetID(), 0, static_cast<int>(event));
185 CServiceBroker::GetAppMessenger()->SendGUIMessage(m);
190 bool CGUIWindowPVRBase::OnAction(const CAction& action)
192 switch (action.GetID())
194 case ACTION_PREVIOUS_CHANNELGROUP:
195 ActivatePreviousChannelGroup();
196 return true;
198 case ACTION_NEXT_CHANNELGROUP:
199 ActivateNextChannelGroup();
200 return true;
202 case ACTION_MOVE_RIGHT:
203 case ACTION_MOVE_LEFT:
205 if (m_channelGroupsSelector->HasFocus() && CGUIMediaWindow::OnAction(action))
207 SetChannelGroup(m_channelGroupsSelector->GetSelectedChannelGroup());
208 return true;
213 return CGUIMediaWindow::OnAction(action);
216 bool CGUIWindowPVRBase::ActivatePreviousChannelGroup()
218 const std::shared_ptr<const CPVRChannelGroup> channelGroup = GetChannelGroup();
219 if (channelGroup)
221 const CPVRChannelGroups* groups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(channelGroup->IsRadio());
222 if (groups)
224 SetChannelGroup(groups->GetPreviousGroup(*channelGroup));
225 return true;
228 return false;
231 bool CGUIWindowPVRBase::ActivateNextChannelGroup()
233 const std::shared_ptr<const CPVRChannelGroup> channelGroup = GetChannelGroup();
234 if (channelGroup)
236 const CPVRChannelGroups* groups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(channelGroup->IsRadio());
237 if (groups)
239 SetChannelGroup(groups->GetNextGroup(*channelGroup));
240 return true;
243 return false;
246 void CGUIWindowPVRBase::ClearData()
248 std::unique_lock<CCriticalSection> lock(m_critSection);
249 m_channelGroup.reset();
250 m_channelGroupsSelector = std::make_unique<CGUIPVRChannelGroupsSelector>();
253 void CGUIWindowPVRBase::OnInitWindow()
255 SetProperty("IsRadio", m_bRadio ? "true" : "");
257 if (InitChannelGroup())
259 m_channelGroupsSelector->Initialize(this, m_bRadio);
261 CGUIMediaWindow::OnInitWindow();
263 // mark item as selected by channel path
264 m_viewControl.SetSelectedItem(
265 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetSelectedChannelPath(m_bRadio));
267 // This has to be done after base class OnInitWindow to restore correct selection
268 m_channelGroupsSelector->SelectChannelGroup(GetChannelGroup());
270 else
272 CGUIWindow::OnInitWindow(); // do not call CGUIMediaWindow as it will do a Refresh which in no case works in this state (no channelgroup!)
273 ShowProgressDialog(g_localizeStrings.Get(19235), 0); // PVR manager is starting up
277 void CGUIWindowPVRBase::OnDeinitWindow(int nextWindowID)
279 HideProgressDialog();
280 UpdateSelectedItemPath();
281 CGUIMediaWindow::OnDeinitWindow(nextWindowID);
284 bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message)
286 bool bReturn = false;
287 switch (message.GetMessage())
289 case GUI_MSG_CLICKED:
291 switch (message.GetSenderId())
293 case CONTROL_BTNCHANNELGROUPS:
294 return OpenChannelGroupSelectionDialog();
296 case CONTROL_LSTCHANNELGROUPS:
298 switch (message.GetParam1())
300 case ACTION_SELECT_ITEM:
301 case ACTION_MOUSE_LEFT_CLICK:
303 SetChannelGroup(m_channelGroupsSelector->GetSelectedChannelGroup());
304 bReturn = true;
305 break;
310 break;
313 case GUI_MSG_REFRESH_LIST:
315 switch (static_cast<PVREvent>(message.GetParam1()))
317 case PVREvent::ManagerStarted:
318 case PVREvent::ClientsInvalidated:
319 case PVREvent::ChannelGroupsInvalidated:
321 if (InitChannelGroup())
323 m_channelGroupsSelector->Initialize(this, m_bRadio);
324 m_channelGroupsSelector->SelectChannelGroup(GetChannelGroup());
325 HideProgressDialog();
326 Refresh(true);
327 m_viewControl.SetFocused();
329 break;
331 default:
332 break;
335 if (IsActive())
337 // Only the active window must set the selected item path which is shared
338 // between all PVR windows, not the last notified window (observer).
339 UpdateSelectedItemPath();
341 bReturn = true;
342 break;
345 case GUI_MSG_NOTIFY_ALL:
347 switch (message.GetParam1())
349 case GUI_MSG_UPDATE_SOURCES:
351 // removable drive connected/disconnected. base class triggers a window
352 // content refresh, which makes no sense for pvr windows.
353 bReturn = true;
354 break;
356 case GUI_MSG_UPDATE:
358 if (IsActive() && m_bUpdating)
360 // no concurrent updates
361 CLog::LogF(LOGWARNING, "GUI_MSG_UPDATE: Updating in progress");
362 bReturn = true;
364 break;
367 break;
371 return bReturn || CGUIMediaWindow::OnMessage(message);
374 void CGUIWindowPVRBase::SetInvalid()
376 if (m_refreshTimeout.IsTimePast())
378 for (const auto& item : *m_vecItems)
379 item->SetInvalid();
381 CGUIMediaWindow::SetInvalid();
382 m_refreshTimeout.Set(MAX_INVALIDATION_FREQUENCY);
386 bool CGUIWindowPVRBase::CanBeActivated() const
388 // check if there is at least one enabled PVR add-on
389 if (!CServiceBroker::GetAddonMgr().HasAddons(ADDON::AddonType::PVRDLL))
391 HELPERS::ShowOKDialogText(CVariant{19296}, CVariant{19272}); // No PVR add-on enabled, You need a tuner, backend software...
392 return false;
395 return true;
398 bool CGUIWindowPVRBase::OpenChannelGroupSelectionDialog()
400 CGUIDialogSelect* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT);
401 if (!dialog)
402 return false;
404 CFileItemList options;
405 CPVRGUIDirectory::GetChannelGroupsDirectory(m_bRadio, true, options);
407 dialog->Reset();
408 dialog->SetHeading(CVariant{g_localizeStrings.Get(19146)});
409 dialog->SetMultiSelection(false);
411 auto& pvrMgr = CServiceBroker::GetPVRManager();
412 const bool useDetails = pvrMgr.Clients()->CreatedClientAmount() > 1;
413 dialog->SetUseDetails(useDetails);
414 if (useDetails)
416 std::string selectedName;
417 std::string selectedClient;
419 const std::shared_ptr<const CPVRChannelGroup> channelGroup = GetChannelGroup();
420 if (channelGroup)
422 selectedName = channelGroup->GroupName();
424 auto client = pvrMgr.GetClient(channelGroup->GetClientID());
425 if (client)
426 selectedClient = client->GetFullClientName();
429 CPVRThumbLoader loader;
430 int idx = 0;
431 for (auto& group : options)
433 // set client name as label2
434 const std::shared_ptr<const CPVRClient> client = pvrMgr.GetClient(*group);
435 if (client)
436 group->SetLabel2(client->GetFullClientName());
438 // set thumbnail
439 loader.LoadItem(group.get());
441 // if not yet done, find and select currently active channel group
442 if (idx >= 0)
444 if (group->GetLabel() == selectedName && group->GetLabel2() == selectedClient)
446 dialog->SetSelected(idx);
447 idx = -1; // done
449 else
451 idx++;
456 else
458 const std::shared_ptr<const CPVRChannelGroup> channelGroup = GetChannelGroup();
459 if (channelGroup)
461 int idx = -1;
462 const std::string selectedName = channelGroup->GroupName();
463 for (auto& group : options)
465 // select currently active channel group
466 if (group->GetLabel() == selectedName)
468 dialog->SetSelected(idx);
469 break;
471 idx++;
476 dialog->SetItems(options);
478 dialog->Open();
480 if (!dialog->IsConfirmed())
481 return false;
483 const CFileItemPtr item = dialog->GetSelectedFileItem();
484 if (!item)
485 return false;
487 SetChannelGroup(pvrMgr.ChannelGroups()->Get(m_bRadio)->GetGroupByPath(item->GetPath()));
489 return true;
492 bool CGUIWindowPVRBase::InitChannelGroup()
494 if (!CServiceBroker::GetPVRManager().IsStarted())
495 return false;
497 std::shared_ptr<CPVRChannelGroup> group;
498 if (m_channelGroupPath.empty())
500 group = CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(m_bRadio);
502 else
504 group = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bRadio)->GetGroupByPath(m_channelGroupPath);
505 if (group)
506 CServiceBroker::GetPVRManager().PlaybackState()->SetActiveChannelGroup(group);
507 else
508 CLog::LogF(LOGERROR, "Found no {} channel group with path '{}'!", m_bRadio ? "radio" : "TV",
509 m_channelGroupPath);
511 m_channelGroupPath.clear();
514 if (group)
516 std::unique_lock<CCriticalSection> lock(m_critSection);
517 if (m_channelGroup != group)
519 m_viewControl.SetSelectedItem(0);
520 SetChannelGroup(std::move(group), false);
522 // Path might have changed since last init. Set it always, not just on group change.
523 m_vecItems->SetPath(GetDirectoryPath());
524 return true;
526 return false;
529 std::shared_ptr<CPVRChannelGroup> CGUIWindowPVRBase::GetChannelGroup()
531 std::unique_lock<CCriticalSection> lock(m_critSection);
532 return m_channelGroup;
535 void CGUIWindowPVRBase::SetChannelGroup(std::shared_ptr<CPVRChannelGroup> &&group, bool bUpdate /* = true */)
537 if (!group)
538 return;
540 std::shared_ptr<CPVRChannelGroup> updateChannelGroup;
542 std::unique_lock<CCriticalSection> lock(m_critSection);
543 if (m_channelGroup != group)
545 if (m_channelGroup)
546 m_channelGroup->Events().Unsubscribe(this);
547 m_channelGroup = std::move(group);
548 // we need to register the window to receive changes from the new group
549 m_channelGroup->Events().Subscribe(this, &CGUIWindowPVRBase::Notify);
550 if (bUpdate)
551 updateChannelGroup = m_channelGroup;
555 if (updateChannelGroup)
557 CServiceBroker::GetPVRManager().PlaybackState()->SetActiveChannelGroup(updateChannelGroup);
558 Update(GetDirectoryPath());
562 bool CGUIWindowPVRBase::Update(const std::string& strDirectory, bool updateFilterPath /*= true*/)
564 if (m_bUpdating)
566 // no concurrent updates
567 CLog::LogF(LOGWARNING, "Updating in progress");
568 return false;
571 CUpdateGuard guard(m_bUpdating);
573 if (!GetChannelGroup())
575 // no updates before fully initialized
576 return false;
579 int iOldCount = m_vecItems->Size();
580 int iSelectedItem = m_viewControl.GetSelectedItem();
581 const std::string oldPath = m_vecItems->GetPath();
583 bool bReturn = CGUIMediaWindow::Update(strDirectory, updateFilterPath);
585 if (bReturn &&
586 iSelectedItem != -1) // something must have been selected
588 int iNewCount = m_vecItems->Size();
589 if (iOldCount > iNewCount && // at least one item removed by Update()
590 oldPath == m_vecItems->GetPath()) // update not due changing into another folder
592 // restore selected item if we just deleted one or more items.
593 if (iSelectedItem >= iNewCount)
594 iSelectedItem = iNewCount - 1;
596 m_viewControl.SetSelectedItem(iSelectedItem);
600 return bReturn;
603 void CGUIWindowPVRBase::UpdateButtons()
605 CGUIMediaWindow::UpdateButtons();
607 const std::shared_ptr<CPVRChannelGroup> channelGroup = GetChannelGroup();
608 if (channelGroup)
610 SET_CONTROL_LABEL(CONTROL_BTNCHANNELGROUPS, g_localizeStrings.Get(19141) + ": " + channelGroup->GroupName());
613 m_channelGroupsSelector->SelectChannelGroup(channelGroup);
616 void CGUIWindowPVRBase::ShowProgressDialog(const std::string& strText, int iProgress)
618 if (!m_progressHandle)
620 CGUIDialogExtendedProgressBar* loadingProgressDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogExtendedProgressBar>(WINDOW_DIALOG_EXT_PROGRESS);
621 if (!loadingProgressDialog)
623 CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_EXT_PROGRESS!");
624 return;
626 m_progressHandle = loadingProgressDialog->GetHandle(g_localizeStrings.Get(19235)); // PVR manager is starting up
629 m_progressHandle->SetPercentage(static_cast<float>(iProgress));
630 m_progressHandle->SetText(strText);
633 void CGUIWindowPVRBase::HideProgressDialog()
635 if (m_progressHandle)
637 m_progressHandle->MarkFinished();
638 m_progressHandle = nullptr;