[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / windows / GUIWindowPVRGuide.cpp
blob6ce75fd5f2bc89da63d0c31e84b246fae5a2d953
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 "GUIWindowPVRGuide.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIUserMessages.h"
14 #include "ServiceBroker.h"
15 #include "addons/Skin.h"
16 #include "dialogs/GUIDialogBusy.h"
17 #include "dialogs/GUIDialogContextMenu.h"
18 #include "dialogs/GUIDialogNumeric.h"
19 #include "guilib/GUIMessage.h"
20 #include "guilib/GUIWindowManager.h"
21 #include "guilib/LocalizeStrings.h"
22 #include "input/actions/Action.h"
23 #include "input/actions/ActionIDs.h"
24 #include "messaging/ApplicationMessenger.h"
25 #include "messaging/helpers/DialogHelper.h"
26 #include "pvr/PVRItem.h"
27 #include "pvr/PVRManager.h"
28 #include "pvr/PVRPlaybackState.h"
29 #include "pvr/channels/PVRChannel.h"
30 #include "pvr/channels/PVRChannelGroup.h"
31 #include "pvr/channels/PVRChannelGroupMember.h"
32 #include "pvr/channels/PVRChannelGroupsContainer.h"
33 #include "pvr/channels/PVRChannelsPath.h"
34 #include "pvr/epg/EpgChannelData.h"
35 #include "pvr/epg/EpgContainer.h"
36 #include "pvr/epg/EpgInfoTag.h"
37 #include "pvr/guilib/GUIEPGGridContainer.h"
38 #include "pvr/guilib/PVRGUIActionsChannels.h"
39 #include "pvr/guilib/PVRGUIActionsEPG.h"
40 #include "pvr/guilib/PVRGUIActionsPlayback.h"
41 #include "pvr/guilib/PVRGUIActionsTimers.h"
42 #include "pvr/recordings/PVRRecordings.h"
43 #include "pvr/timers/PVRTimers.h"
44 #include "settings/Settings.h"
45 #include "settings/SettingsComponent.h"
46 #include "view/GUIViewState.h"
48 #include <functional>
49 #include <memory>
50 #include <mutex>
51 #include <utility>
52 #include <vector>
54 using namespace KODI::MESSAGING;
55 using namespace PVR;
56 using namespace std::chrono_literals;
58 CGUIWindowPVRGuideBase::CGUIWindowPVRGuideBase(bool bRadio, int id, const std::string& xmlFile)
59 : CGUIWindowPVRBase(bRadio, id, xmlFile)
61 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().RegisterChannelNumberInputHandler(this);
64 CGUIWindowPVRGuideBase::~CGUIWindowPVRGuideBase()
66 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().DeregisterChannelNumberInputHandler(
67 this);
69 m_bRefreshTimelineItems = false;
70 m_bSyncRefreshTimelineItems = false;
71 StopRefreshTimelineItemsThread();
74 CGUIEPGGridContainer* CGUIWindowPVRGuideBase::GetGridControl()
76 return dynamic_cast<CGUIEPGGridContainer*>(GetControl(m_viewControl.GetCurrentControl()));
79 void CGUIWindowPVRGuideBase::InitEpgGridControl()
81 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
82 if (epgGridContainer)
84 CPVRManager& mgr = CServiceBroker::GetPVRManager();
86 const std::shared_ptr<CPVRChannel> channel = mgr.ChannelGroups()->GetByPath(
87 mgr.Get<PVR::GUI::Channels>().GetSelectedChannelPath(m_bRadio));
89 if (channel)
91 m_bChannelSelectionRestored = epgGridContainer->SetChannel(channel);
92 epgGridContainer->JumpToDate(
93 mgr.PlaybackState()->GetPlaybackTime(channel->ClientID(), channel->UniqueID()));
95 else
97 m_bChannelSelectionRestored = false;
98 epgGridContainer->JumpToNow();
101 if (!epgGridContainer->HasData())
102 m_bSyncRefreshTimelineItems = true; // force data update on first window open
105 StartRefreshTimelineItemsThread();
108 void CGUIWindowPVRGuideBase::ClearData()
111 std::unique_lock<CCriticalSection> lock(m_critSection);
112 m_cachedChannelGroup.reset();
115 CGUIWindowPVRBase::ClearData();
118 void CGUIWindowPVRGuideBase::OnInitWindow()
120 if (m_guiState)
121 m_viewControl.SetCurrentView(m_guiState->GetViewAsControl(), false);
123 if (InitChannelGroup()) // no channels -> lazy init
124 InitEpgGridControl();
126 CGUIWindowPVRBase::OnInitWindow();
129 void CGUIWindowPVRGuideBase::OnDeinitWindow(int nextWindowID)
131 StopRefreshTimelineItemsThread();
133 m_bChannelSelectionRestored = false;
135 CGUIDialog* dialog =
136 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS);
137 if (dialog && dialog->IsDialogRunning())
139 dialog->Close();
142 CGUIWindowPVRBase::OnDeinitWindow(nextWindowID);
145 void CGUIWindowPVRGuideBase::StartRefreshTimelineItemsThread()
147 StopRefreshTimelineItemsThread();
148 m_refreshTimelineItemsThread = std::make_unique<CPVRRefreshTimelineItemsThread>(this);
149 m_refreshTimelineItemsThread->Create();
152 void CGUIWindowPVRGuideBase::StopRefreshTimelineItemsThread()
154 if (m_refreshTimelineItemsThread)
155 m_refreshTimelineItemsThread->Stop();
158 void CGUIWindowPVRGuideBase::NotifyEvent(const PVREvent& event)
160 if (event == PVREvent::Epg || event == PVREvent::EpgContainer ||
161 event == PVREvent::ChannelGroupInvalidated || event == PVREvent::ChannelGroup)
163 m_bRefreshTimelineItems = true;
164 // no base class call => do async refresh
165 return;
167 else if (event == PVREvent::ChannelPlaybackStopped)
169 if (m_guiState && m_guiState->GetSortMethod().sortBy == SortByLastPlayed)
171 // set dirty to force sync refresh
172 m_bSyncRefreshTimelineItems = true;
176 // do sync refresh if dirty
177 CGUIWindowPVRBase::NotifyEvent(event);
180 void CGUIWindowPVRGuideBase::SetInvalid()
182 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
183 if (epgGridContainer)
184 epgGridContainer->SetInvalid();
186 CGUIWindowPVRBase::SetInvalid();
189 void CGUIWindowPVRGuideBase::GetContextButtons(int itemNumber, CContextButtons& buttons)
191 CGUIWindowPVRBase::GetContextButtons(itemNumber, buttons);
193 buttons.Add(CONTEXT_BUTTON_NAVIGATE, 19326); // Navigate...
196 void CGUIWindowPVRGuideBase::UpdateSelectedItemPath()
198 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
199 if (epgGridContainer)
201 const std::shared_ptr<const CPVRChannelGroupMember> groupMember =
202 epgGridContainer->GetSelectedChannelGroupMember();
203 if (groupMember)
204 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().SetSelectedChannelPath(
205 m_bRadio, groupMember->Path());
209 void CGUIWindowPVRGuideBase::UpdateButtons()
211 CGUIWindowPVRBase::UpdateButtons();
213 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1, g_localizeStrings.Get(19032));
215 const std::shared_ptr<const CPVRChannelGroup> group = GetChannelGroup();
216 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2, group ? group->GroupName() : "");
219 bool CGUIWindowPVRGuideBase::Update(const std::string& strDirectory,
220 bool updateFilterPath /* = true */)
222 if (m_bUpdating)
224 // Prevent concurrent updates. Instead, let the timeline items refresh thread pick it up later.
225 m_bRefreshTimelineItems = true;
226 return true;
229 bool bReturn = CGUIWindowPVRBase::Update(strDirectory, updateFilterPath);
231 if (bReturn && !m_bChannelSelectionRestored)
233 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
234 if (epgGridContainer)
235 m_bChannelSelectionRestored = epgGridContainer->SetChannel(
236 CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetSelectedChannelPath(
237 m_bRadio));
240 return bReturn;
243 bool CGUIWindowPVRGuideBase::GetDirectory(const std::string& strDirectory, CFileItemList& items)
246 std::unique_lock<CCriticalSection> lock(m_critSection);
248 if (m_cachedChannelGroup && *m_cachedChannelGroup != *GetChannelGroup())
250 // channel group change and not very first open of this window. force immediate update.
251 m_bSyncRefreshTimelineItems = true;
255 if (m_bSyncRefreshTimelineItems)
256 m_refreshTimelineItemsThread->DoRefresh(true);
258 const CGUIEPGGridContainer* epgGridContainer = GetGridControl();
259 if (epgGridContainer)
261 const std::unique_ptr<CFileItemList> newTimeline = GetGridControl()->GetCurrentTimeLineItems();
262 items.RemoveDiscCache(GetID());
263 items.Assign(*newTimeline, false);
266 return true;
269 void CGUIWindowPVRGuideBase::FormatAndSort(CFileItemList& items)
271 // Speedup: Nothing to do here as sorting was already done in RefreshTimelineItems
272 return;
275 CFileItemPtr CGUIWindowPVRGuideBase::GetCurrentListItem(int offset /*= 0*/)
277 const CGUIEPGGridContainer* epgGridContainer = GetGridControl();
278 if (epgGridContainer)
279 return epgGridContainer->GetSelectedGridItem(offset);
281 return {};
284 int CGUIWindowPVRGuideBase::GetCurrentListItemIndex(const std::shared_ptr<const CFileItem>& item)
286 return item ? item->GetProperty("TimelineIndex").asInteger() : -1;
289 bool CGUIWindowPVRGuideBase::ShouldNavigateToGridContainer(int iAction)
291 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
292 CGUIControl* control = GetControl(CONTROL_LSTCHANNELGROUPS);
293 if (epgGridContainer && control && GetFocusedControlID() == control->GetID())
295 int iNavigationId = control->GetAction(iAction).GetNavigation();
296 if (iNavigationId > 0)
298 control = epgGridContainer;
299 while (control !=
300 this) // navigation target could be the grid control or one of its parent controls.
302 if (iNavigationId == control->GetID())
304 // channel group selector control's target for the action is the grid control
305 return true;
307 control = control->GetParentControl();
311 return false;
314 bool CGUIWindowPVRGuideBase::OnAction(const CAction& action)
316 switch (action.GetID())
318 case ACTION_MOVE_UP:
319 case ACTION_MOVE_DOWN:
320 case ACTION_MOVE_LEFT:
321 case ACTION_MOVE_RIGHT:
323 // Check whether grid container is configured as channel group selector's navigation target for the given action.
324 if (ShouldNavigateToGridContainer(action.GetID()))
326 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
327 if (epgGridContainer)
329 CGUIWindowPVRBase::OnAction(action);
331 switch (action.GetID())
333 case ACTION_MOVE_UP:
334 epgGridContainer->GoToBottom();
335 return true;
336 case ACTION_MOVE_DOWN:
337 epgGridContainer->GoToTop();
338 return true;
339 case ACTION_MOVE_LEFT:
340 epgGridContainer->GoToMostRight();
341 return true;
342 case ACTION_MOVE_RIGHT:
343 epgGridContainer->GoToMostLeft();
344 return true;
345 default:
346 break;
350 break;
352 case REMOTE_0:
353 if (GetCurrentDigitCount() == 0)
355 // single zero input is handled by epg grid container
356 break;
358 // fall-thru is intended
359 [[fallthrough]];
360 case REMOTE_1:
361 case REMOTE_2:
362 case REMOTE_3:
363 case REMOTE_4:
364 case REMOTE_5:
365 case REMOTE_6:
366 case REMOTE_7:
367 case REMOTE_8:
368 case REMOTE_9:
369 AppendChannelNumberCharacter(static_cast<char>(action.GetID() - REMOTE_0) + '0');
370 return true;
372 case ACTION_CHANNEL_NUMBER_SEP:
373 AppendChannelNumberCharacter(CPVRChannelNumber::SEPARATOR);
374 return true;
377 return CGUIWindowPVRBase::OnAction(action);
380 void CGUIWindowPVRGuideBase::RefreshView(CGUIMessage& message, bool bInitGridControl)
382 CGUIWindowPVRBase::OnMessage(message);
384 // force grid data update
385 m_bSyncRefreshTimelineItems = true;
387 if (bInitGridControl)
388 InitEpgGridControl();
390 Refresh(true);
393 bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message)
395 bool bReturn = false;
396 switch (message.GetMessage())
398 case GUI_MSG_WINDOW_INIT:
400 const CPVRChannelsPath path(message.GetStringParam(0));
401 if (path.IsValid() && path.IsChannelGroup())
403 // if a path to a channel group is given we must init
404 // that group instead of last played/selected group
405 m_channelGroupPath = message.GetStringParam(0);
407 break;
410 case GUI_MSG_ITEM_SELECTED:
411 message.SetParam1(GetCurrentListItemIndex(GetCurrentListItem()));
412 bReturn = true;
413 break;
415 case GUI_MSG_CLICKED:
417 if (message.GetSenderId() == m_viewControl.GetCurrentControl())
419 if (message.GetParam1() == ACTION_SELECT_ITEM ||
420 message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)
422 // If direct channel number input is active, select the entered channel.
423 if (CServiceBroker::GetPVRManager()
424 .Get<PVR::GUI::Channels>()
425 .GetChannelNumberInputHandler()
426 .CheckInputAndExecuteAction())
428 bReturn = true;
429 break;
433 const std::shared_ptr<CFileItem> pItem = GetCurrentListItem();
434 if (pItem)
436 switch (message.GetParam1())
438 case ACTION_SELECT_ITEM:
439 case ACTION_MOUSE_LEFT_CLICK:
440 switch (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
441 CSettings::SETTING_EPG_SELECTACTION))
443 case EPG_SELECT_ACTION_CONTEXT_MENU:
444 OnPopupMenu(GetCurrentListItemIndex(pItem));
445 bReturn = true;
446 break;
447 case EPG_SELECT_ACTION_SWITCH:
448 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(*pItem,
449 true);
450 bReturn = true;
451 break;
452 case EPG_SELECT_ACTION_PLAY_RECORDING:
453 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(*pItem,
454 true);
455 bReturn = true;
456 break;
457 case EPG_SELECT_ACTION_INFO:
458 CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(*pItem);
459 bReturn = true;
460 break;
461 case EPG_SELECT_ACTION_RECORD:
462 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(*pItem);
463 bReturn = true;
464 break;
465 case EPG_SELECT_ACTION_SMART_SELECT:
467 const std::shared_ptr<const CPVREpgInfoTag> tag(pItem->GetEPGInfoTag());
468 if (tag)
470 const CDateTime start(tag->StartAsUTC());
471 const CDateTime end(tag->EndAsUTC());
472 const CDateTime now(CDateTime::GetUTCDateTime());
474 if (start <= now && now <= end)
476 // current event
477 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(
478 *pItem, true);
480 else if (now < start)
482 // future event
483 if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag))
484 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().EditTimer(*pItem);
485 else
487 bool bCanRecord = true;
488 const std::shared_ptr<const CPVRChannel> channel =
489 CPVRItem(pItem).GetChannel();
490 if (channel)
491 bCanRecord = channel->CanRecord();
493 const int iTextID =
494 bCanRecord
495 ? 19302 // "Do you want to record the selected programme or to switch to the current programme?"
496 : 19344; // "Do you want to set a reminder for the selected programme or to switch to the current programme?"
497 const int iNoButtonID = bCanRecord ? 264 // No => "Record"
498 : 826; // "Set reminder"
500 HELPERS::DialogResponse ret =
501 HELPERS::ShowYesNoDialogText(CVariant{19096}, // "Smart select"
502 CVariant{iTextID}, CVariant{iNoButtonID},
503 CVariant{19165}); // Yes => "Switch"
504 if (ret == HELPERS::DialogResponse::CHOICE_NO)
505 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(*pItem,
506 false);
507 else if (ret == HELPERS::DialogResponse::CHOICE_YES)
508 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(
509 *pItem, true);
512 else
514 // past event
515 if (CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag))
516 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
517 *pItem, true);
518 else if (tag->IsPlayable())
519 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayEpgTag(
520 *pItem);
521 else
522 CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(*pItem);
524 bReturn = true;
526 break;
529 break;
530 case ACTION_SHOW_INFO:
531 CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(*pItem);
532 bReturn = true;
533 break;
534 case ACTION_PLAYER_PLAY:
535 CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(*pItem,
536 true);
537 bReturn = true;
538 break;
539 case ACTION_RECORD:
540 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(*pItem);
541 bReturn = true;
542 break;
543 case ACTION_PVR_SHOW_TIMER_RULE:
544 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimerRule(*pItem, true,
545 false);
546 bReturn = true;
547 break;
548 case ACTION_CONTEXT_MENU:
549 case ACTION_MOUSE_RIGHT_CLICK:
550 OnPopupMenu(GetCurrentListItemIndex(pItem));
551 bReturn = true;
552 break;
556 else if (message.GetSenderId() == CONTROL_BTNVIEWASICONS ||
557 message.GetSenderId() == CONTROL_BTNSORTBY ||
558 message.GetSenderId() == CONTROL_BTNSORTASC)
560 RefreshView(message, false);
561 bReturn = true;
563 break;
565 case GUI_MSG_CHANGE_SORT_DIRECTION:
566 case GUI_MSG_CHANGE_SORT_METHOD:
567 case GUI_MSG_CHANGE_VIEW_MODE:
569 RefreshView(message, message.GetMessage() == GUI_MSG_CHANGE_VIEW_MODE);
570 bReturn = true;
571 break;
573 case GUI_MSG_REFRESH_LIST:
575 switch (static_cast<PVREvent>(message.GetParam1()))
577 case PVREvent::ManagerStarted:
578 if (InitChannelGroup())
579 InitEpgGridControl();
580 break;
582 case PVREvent::ChannelGroup:
583 case PVREvent::ChannelGroupInvalidated:
584 case PVREvent::ClientsInvalidated:
585 case PVREvent::ChannelPlaybackStopped:
586 case PVREvent::Epg:
587 case PVREvent::EpgContainer:
588 if (InitChannelGroup())
589 Refresh(true);
590 break;
592 case PVREvent::Timers:
593 case PVREvent::TimersInvalidated:
594 SetInvalid();
595 break;
597 default:
598 break;
600 break;
602 case GUI_MSG_SYSTEM_WAKE:
603 GotoCurrentProgramme();
604 bReturn = true;
605 break;
608 return bReturn || CGUIWindowPVRBase::OnMessage(message);
611 bool CGUIWindowPVRGuideBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
613 if (OnContextButtonNavigate(button))
614 return true;
616 if (itemNumber < 0 || itemNumber >= m_vecItems->Size())
617 return false;
619 return CGUIMediaWindow::OnContextButton(itemNumber, button);
622 namespace
625 template<typename A>
626 class CContextMenuFunctions : public CContextButtons
628 public:
629 explicit CContextMenuFunctions(A* instance) : m_instance(instance) {}
631 void Add(bool (A::*function)(), unsigned int resId)
633 CContextButtons::Add(size(), resId);
634 m_functions.emplace_back(std::bind(function, m_instance));
637 bool Call(int idx)
639 if (idx < 0 || idx >= static_cast<int>(m_functions.size()))
640 return false;
642 return m_functions[idx]();
645 private:
646 A* m_instance = nullptr;
647 std::vector<std::function<bool()>> m_functions;
650 } // unnamed namespace
652 bool CGUIWindowPVRGuideBase::OnContextButtonNavigate(CONTEXT_BUTTON button)
654 bool bReturn = false;
656 if (button == CONTEXT_BUTTON_NAVIGATE)
658 if (g_SkinInfo->HasSkinFile("DialogPVRGuideControls.xml"))
660 // use controls dialog
661 CGUIDialog* dialog =
662 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS);
663 if (dialog && !dialog->IsDialogRunning())
665 dialog->Open();
668 else
670 // use context menu
671 CContextMenuFunctions<CGUIWindowPVRGuideBase> buttons(this);
672 buttons.Add(&CGUIWindowPVRGuideBase::GotoBegin, 19063); // First programme
673 buttons.Add(&CGUIWindowPVRGuideBase::Go12HoursBack, 19317); // 12 hours back
674 buttons.Add(&CGUIWindowPVRGuideBase::GotoCurrentProgramme, 19070); // Current programme
675 buttons.Add(&CGUIWindowPVRGuideBase::Go12HoursForward, 19318); // 12 hours forward
676 buttons.Add(&CGUIWindowPVRGuideBase::GotoEnd, 19064); // Last programme
677 buttons.Add(&CGUIWindowPVRGuideBase::OpenDateSelectionDialog, 19288); // Date selector
678 buttons.Add(&CGUIWindowPVRGuideBase::GotoFirstChannel, 19322); // First channel
679 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV() ||
680 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio() ||
681 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag())
682 buttons.Add(&CGUIWindowPVRGuideBase::GotoPlayingChannel, 19323); // Playing channel
683 buttons.Add(&CGUIWindowPVRGuideBase::GotoLastChannel, 19324); // Last channel
684 buttons.Add(&CGUIWindowPVRBase::ActivatePreviousChannelGroup, 19319); // Previous group
685 buttons.Add(&CGUIWindowPVRBase::ActivateNextChannelGroup, 19320); // Next group
686 buttons.Add(&CGUIWindowPVRBase::OpenChannelGroupSelectionDialog, 19321); // Group selector
688 int buttonIdx = 0;
689 int lastButtonIdx = 2; // initially select "Current programme"
691 // loop until canceled
692 while (buttonIdx >= 0)
694 buttonIdx = CGUIDialogContextMenu::Show(buttons, lastButtonIdx);
695 lastButtonIdx = buttonIdx;
696 buttons.Call(buttonIdx);
699 bReturn = true;
702 return bReturn;
705 bool CGUIWindowPVRGuideBase::RefreshTimelineItems()
707 if (m_bRefreshTimelineItems || m_bSyncRefreshTimelineItems)
709 m_bRefreshTimelineItems = false;
710 m_bSyncRefreshTimelineItems = false;
712 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
713 if (epgGridContainer)
715 const std::shared_ptr<CPVRChannelGroup> group(GetChannelGroup());
716 if (!group)
717 return false;
719 CPVREpgContainer& epgContainer = CServiceBroker::GetPVRManager().EpgContainer();
721 const std::pair<CDateTime, CDateTime> dates = epgContainer.GetFirstAndLastEPGDate();
722 CDateTime startDate = dates.first;
723 CDateTime endDate = dates.second;
724 const CDateTime currentDate = CDateTime::GetUTCDateTime();
726 if (!startDate.IsValid())
727 startDate = currentDate;
729 if (!endDate.IsValid() || endDate < startDate)
730 endDate = startDate;
732 // limit start to past days to display
733 const int iPastDays = epgContainer.GetPastDaysToDisplay();
734 const CDateTime maxPastDate(currentDate - CDateTimeSpan(iPastDays, 0, 0, 0));
735 if (startDate < maxPastDate)
736 startDate = maxPastDate;
738 // limit end to future days to display
739 const int iFutureDays = epgContainer.GetFutureDaysToDisplay();
740 const CDateTime maxFutureDate(currentDate + CDateTimeSpan(iFutureDays, 0, 0, 0));
741 if (endDate > maxFutureDate)
742 endDate = maxFutureDate;
744 std::unique_ptr<CFileItemList> channels(new CFileItemList);
745 const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers =
746 group->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE);
748 for (const auto& groupMember : groupMembers)
750 channels->Add(std::make_shared<CFileItem>(groupMember));
753 if (m_guiState)
754 channels->Sort(m_guiState->GetSortMethod());
756 epgGridContainer->SetTimelineItems(channels, startDate, endDate);
759 std::unique_lock<CCriticalSection> lock(m_critSection);
760 m_cachedChannelGroup = group;
762 return true;
765 return false;
768 bool CGUIWindowPVRGuideBase::GotoBegin()
770 GetGridControl()->GoToBegin();
771 return true;
774 bool CGUIWindowPVRGuideBase::GotoEnd()
776 GetGridControl()->GoToEnd();
777 return true;
780 bool CGUIWindowPVRGuideBase::GotoCurrentProgramme()
782 const CPVRManager& mgr = CServiceBroker::GetPVRManager();
783 std::shared_ptr<CPVRChannel> channel = mgr.PlaybackState()->GetPlayingChannel();
785 if (!channel)
787 const std::shared_ptr<const CPVREpgInfoTag> playingTag =
788 mgr.PlaybackState()->GetPlayingEpgTag();
789 if (playingTag)
790 channel = mgr.ChannelGroups()->GetChannelForEpgTag(playingTag);
793 if (channel)
794 GetGridControl()->GoToDate(
795 mgr.PlaybackState()->GetPlaybackTime(channel->ClientID(), channel->UniqueID()));
796 else
797 GetGridControl()->GoToNow();
799 return true;
802 bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog()
804 bool bReturn = false;
806 KODI::TIME::SystemTime date;
807 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
808 epgGridContainer->GetSelectedDate().GetAsSystemTime(date);
810 if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(19288))) /* Go to date */
812 epgGridContainer->GoToDate(CDateTime(date));
813 bReturn = true;
816 return bReturn;
819 bool CGUIWindowPVRGuideBase::Go12HoursBack()
821 return GotoDate(-12);
824 bool CGUIWindowPVRGuideBase::Go12HoursForward()
826 return GotoDate(+12);
829 bool CGUIWindowPVRGuideBase::GotoDate(int deltaHours)
831 CGUIEPGGridContainer* epgGridContainer = GetGridControl();
832 epgGridContainer->GoToDate(epgGridContainer->GetSelectedDate() +
833 CDateTimeSpan(0, deltaHours, 0, 0));
834 return true;
837 bool CGUIWindowPVRGuideBase::GotoFirstChannel()
839 GetGridControl()->GoToFirstChannel();
840 return true;
843 bool CGUIWindowPVRGuideBase::GotoLastChannel()
845 GetGridControl()->GoToLastChannel();
846 return true;
849 bool CGUIWindowPVRGuideBase::GotoPlayingChannel()
851 const CPVRManager& mgr = CServiceBroker::GetPVRManager();
852 std::shared_ptr<CPVRChannel> channel = mgr.PlaybackState()->GetPlayingChannel();
854 if (!channel)
856 const std::shared_ptr<const CPVREpgInfoTag> playingTag =
857 mgr.PlaybackState()->GetPlayingEpgTag();
858 if (playingTag)
859 channel = mgr.ChannelGroups()->GetChannelForEpgTag(playingTag);
862 if (channel)
864 GetGridControl()->SetChannel(channel);
865 return true;
867 return false;
870 void CGUIWindowPVRGuideBase::OnInputDone()
872 const CPVRChannelNumber channelNumber = GetChannelNumber();
873 if (channelNumber.IsValid())
875 GetGridControl()->SetChannel(channelNumber);
879 void CGUIWindowPVRGuideBase::GetChannelNumbers(std::vector<std::string>& channelNumbers)
881 const std::shared_ptr<const CPVRChannelGroup> group = GetChannelGroup();
882 if (group)
883 group->GetChannelNumbers(channelNumbers);
886 CPVRRefreshTimelineItemsThread::CPVRRefreshTimelineItemsThread(CGUIWindowPVRGuideBase* pGuideWindow)
887 : CThread("epg-grid-refresh-timeline-items"),
888 m_pGuideWindow(pGuideWindow),
889 m_ready(true),
890 m_done(false)
894 CPVRRefreshTimelineItemsThread::~CPVRRefreshTimelineItemsThread()
896 // Note: CThread dtor will also call StopThread(true), but if thread worker function exits that
897 // late, it might access member variables of this which are already destroyed. Thus, stop
898 // the thread worker here and synchronously, while all members of this are still alive.
899 StopThread(true);
902 void CPVRRefreshTimelineItemsThread::Stop()
904 StopThread(false);
905 m_ready.Set(); // wake up the worker thread to let it exit
908 void CPVRRefreshTimelineItemsThread::DoRefresh(bool bWait)
910 m_ready.Set(); // wake up the worker thread
912 if (bWait)
914 m_done.Reset();
915 CGUIDialogBusy::WaitOnEvent(m_done, 100, false);
919 void CPVRRefreshTimelineItemsThread::Process()
921 static const int BOOSTED_SLEEPS_THRESHOLD = 4;
923 int iLastEpgItemsCount = 0;
924 int iUpdatesWithoutChange = 0;
926 while (!m_bStop)
928 m_done.Reset();
930 if (m_pGuideWindow->RefreshTimelineItems() && !m_bStop)
932 CGUIMessage m(GUI_MSG_REFRESH_LIST, m_pGuideWindow->GetID(), 0,
933 static_cast<int>(PVREvent::Epg));
934 CServiceBroker::GetAppMessenger()->SendGUIMessage(m);
937 if (m_bStop)
938 break;
940 m_done.Set();
942 // in order to fill the guide window asap, use a short update interval until we the
943 // same amount of epg events for BOOSTED_SLEEPS_THRESHOLD + 1 times in a row .
944 if (iUpdatesWithoutChange < BOOSTED_SLEEPS_THRESHOLD)
946 int iCurrentEpgItemsCount = m_pGuideWindow->CurrentDirectory().Size();
948 if (iCurrentEpgItemsCount == iLastEpgItemsCount)
949 iUpdatesWithoutChange++;
950 else
951 iUpdatesWithoutChange = 0; // reset
953 iLastEpgItemsCount = iCurrentEpgItemsCount;
955 m_ready.Wait(1000ms); // boosted update cycle
957 else
959 m_ready.Wait(5000ms); // normal update cycle
962 m_ready.Reset();
965 m_ready.Reset();
966 m_done.Set();
969 std::string CGUIWindowPVRTVGuide::GetRootPath() const
971 return "pvr://guide/tv/";
974 std::string CGUIWindowPVRRadioGuide::GetRootPath() const
976 return "pvr://guide/radio/";