MythTV master
mythfrontend.cpp
Go to the documentation of this file.
1#include "libmythbase/mythconfig.h"
2
3// C/C++
4#include <cerrno>
5#include <csignal>
6#include <cstdlib>
7#include <fcntl.h>
8#include <iostream>
9#include <memory>
10#include "zlib.h"
11
12// Qt
13#include <QtGlobal>
14#ifdef Q_OS_ANDROID
15#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
16#include <QtAndroidExtras>
17#else
18#include <QCoreApplication>
19#include <QJniObject>
20#define QAndroidJniObject QJniObject
21#endif
22#endif
23#include <QApplication>
24#include <QDir>
25#include <QEvent>
26#include <QFile>
27#include <QFileInfo>
28#include <QKeyEvent>
29#include <QMap>
30#ifdef Q_OS_DARWIN
31#include <QProcessEnvironment>
32#endif
33#include <QTimer>
34#if CONFIG_QTWEBENGINE
35#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
36#include <QtWebEngineQuick>
37#else
38#include <QtWebEngine>
39#endif
40#endif
41
42// MythTV
45#include "libmyth/mythcontext.h"
47#include "libmythbase/compat.h" // For SIG* on MinGW
54#include "libmythbase/mythdb.h"
62#include "libmythbase/mythversion.h"
68#include "libmythtv/dbcheck.h"
70#include "libmythtv/playgroup.h"
74#include "libmythtv/tv.h"
81
82// MythFrontend
85#include "channelrecpriority.h"
86#include "customedit.h"
87#include "custompriority.h"
88#include "exitprompt.h"
89#include "globalsettings.h"
90#include "grabbersettings.h"
91#include "guidegrid.h"
92#include "idlescreen.h"
93#include "manualschedule.h"
94#include "mediarenderer.h"
95#include "mythcontrols.h"
97#include "networkcontrol.h"
98#include "playbackbox.h"
99#include "prevreclist.h"
100#include "progfind.h"
101#include "proglist.h"
102#include "programrecpriority.h"
103#include "scheduleeditor.h"
104#include "settingshelper.h"
105#include "setupwizard_general.h"
106#include "statusbox.h"
107#include "themechooser.h"
108#include "viewscheduled.h"
109
110// Video
111#include "videodlg.h"
112#include "videoglobalsettings.h"
113#include "videofileassoc.h"
114#include "videoplayersettings.h"
116#include "videolist.h"
117
118// Gallery
119#include "gallerythumbview.h"
120
121// DVD & Bluray
125
126// AirPlay
127#if CONFIG_AIRPLAY
130#endif
131
132#if CONFIG_LIBDNS_SD
133#include <QScopedPointer>
135#endif
136#if CONFIG_SYSTEMD_NOTIFY
137#include <systemd/sd-daemon.h>
138static inline void fe_sd_notify(const char *str) { sd_notify(0, str); };
139#else
140static inline void fe_sd_notify(const char */*str*/) {};
141#endif
142
147
149
150static MediaRenderer *g_pUPnp = nullptr;
152
154
155static void handleExit(bool prompt);
156static void resetAllKeys(void);
157void handleSIGUSR1(void);
158void handleSIGUSR2(void);
159
160#ifdef Q_OS_DARWIN
161static bool gLoaded = false;
162#endif
163
164static const QString sLocation = QCoreApplication::translate("(Common)",
165 "MythFrontend");
166
167namespace
168{
169 class RunSettingsCompletion : public QObject
170 {
171 Q_OBJECT
172
173 public:
174 static void Create(bool check)
175 {
176 new RunSettingsCompletion(check);
177 }
178
179 private:
180 explicit RunSettingsCompletion(bool check)
181 {
182 if (check)
183 {
185 this, &RunSettingsCompletion::OnPasswordResultReady);
187 }
188 else
189 {
190 OnPasswordResultReady(true, ParentalLevel::plHigh);
191 }
192 }
193
194 ~RunSettingsCompletion() override = default;
195
196 private slots:
197 void OnPasswordResultReady(bool passwordValid,
198 ParentalLevel::Level newLevel)
199 {
200 (void) newLevel;
201
202 if (passwordValid)
203 {
205 auto *ssd =
206 new StandardSettingDialog(mainStack, "videogeneralsettings",
208
209 if (ssd->Create())
210 {
211 mainStack->AddScreen(ssd);
212 }
213 else
214 {
215 delete ssd;
216 }
217 }
218 else
219 {
220 LOG(VB_GENERAL, LOG_WARNING,
221 "Aggressive Parental Controls Warning: "
222 "invalid password. An attempt to enter a "
223 "MythVideo settings screen was prevented.");
224 }
225
226 deleteLater();
227 }
228
229 public:
231 };
232
237 {
238 Q_DECLARE_TR_FUNCTIONS(BookmarkDialog)
239
240 public:
242 bool bookmarkPresent, bool lastPlayPresent) :
243 MythScreenType(parent, "bookmarkdialog"),
244 m_pgi(pginfo),
245 m_bookmarked(bookmarkPresent),
246 m_lastPlayed(lastPlayPresent),
247 m_btnPlayBookmark(tr("Play from bookmark")),
248 m_btnClearBookmark(tr("Clear bookmark")),
249 m_btnPlayBegin(tr("Play from beginning")),
250 m_btnPlayLast(tr("Play from last played position")),
251 m_btnClearLast(tr("Clear last played position")) {
252 }
253
254 bool Create() override // MythScreenType
255 {
256 QString msg = tr("DVD/Video contains a bookmark");
257
258 m_videoDlg = dynamic_cast<VideoDialog*>(GetScreenStack()->GetTopScreen());
259 auto *popup = new MythDialogBox(msg, GetScreenStack(), "bookmarkdialog");
260 if (!popup->Create())
261 {
262 delete popup;
263 return false;
264 }
265
266 GetScreenStack()->AddScreen(popup);
267
268 popup->SetReturnEvent(this, "bookmarkdialog");
269 if (m_lastPlayed)
270 popup->AddButton(m_btnPlayLast);
271 if (m_bookmarked)
272 popup->AddButton(m_btnPlayBookmark);
273 popup->AddButton(m_btnPlayBegin);
274 if (m_lastPlayed)
275 popup->AddButton(m_btnClearLast);
276 if (m_bookmarked)
277 popup->AddButton(m_btnClearBookmark);
278 return true;
279 }
280
281 void customEvent(QEvent *event) override // MythUIType
282 {
283 if (event->type() != DialogCompletionEvent::kEventType)
284 return;
285
286 auto *dce = (DialogCompletionEvent*)(event);
287 QString buttonText = dce->GetResultText();
288
289 if (dce->GetId() != "bookmarkdialog")
290 return;
291
292 if (buttonText == m_btnPlayLast)
294 else if (buttonText == m_btnPlayBookmark)
296 else if (buttonText == m_btnPlayBegin)
298 else if (buttonText == m_btnClearBookmark)
299 {
300 m_pgi->SaveBookmark(0);
301 if (m_videoDlg)
302 {
303 m_videoDlg->playbackStateChanged(m_pgi->GetBasename());
304 }
305 }
306 else if (buttonText == m_btnClearLast)
307 {
308 m_pgi->SaveLastPlayPos(0);
309 if (m_videoDlg)
310 {
311 m_videoDlg->playbackStateChanged(m_pgi->GetBasename());
312 }
313 }
314 delete m_pgi;
315 }
316
317 private:
318 ProgramInfo* m_pgi {nullptr};
319 bool m_bookmarked {false};
320 bool m_lastPlayed {false};
326 VideoDialog *m_videoDlg {nullptr};
327 };
328
329 void cleanup()
330 {
331 QCoreApplication::processEvents();
332#if CONFIG_AIRPLAY
335#endif
336
338
339 if (g_pUPnp)
340 {
341 // This takes a few seconds, so inform the user:
342 LOG(VB_GENERAL, LOG_INFO, "Shutting down UPnP client...");
343 delete g_pUPnp;
344 g_pUPnp = nullptr;
345 }
346
347 if (g_pmanager)
348 {
349 delete g_pmanager;
350 g_pmanager = nullptr;
351 }
352
354 {
355 delete g_settingsHelper;
356 g_settingsHelper = nullptr;
357 }
358 }
359}
360
361static void startAppearWiz(void)
362{
363 int curX = gCoreContext->GetNumSetting("GuiOffsetX", 0);
364 int curY = gCoreContext->GetNumSetting("GuiOffsetY", 0);
365 int curW = gCoreContext->GetNumSetting("GuiWidth", 0);
366 int curH = gCoreContext->GetNumSetting("GuiHeight", 0);
367
368 bool isWindowed =
369 (gCoreContext->GetNumSetting("RunFrontendInWindow", 0) == 1);
370
371 bool reload = false;
372
373 if (isWindowed)
374 {
375 ShowOkPopup(QCoreApplication::translate("(MythFrontendMain)",
376 "The ScreenSetupWizard cannot be used while "
377 "mythfrontend is operating in windowed mode."));
378 }
379 else
380 {
381 auto *wizard = new MythSystemLegacy(
382 GetAppBinDir() + "mythscreenwizard",
383 QStringList(),
385 wizard->Run();
386
387 if (!wizard->Wait())
388 {
389 // no reported errors, check for changed geometry parameters
390 gCoreContext->ClearSettingsCache("GuiOffsetX");
391 gCoreContext->ClearSettingsCache("GuiOffsetY");
392 gCoreContext->ClearSettingsCache("GuiWidth");
393 gCoreContext->ClearSettingsCache("GuiHeight");
394
395 if ((curX != gCoreContext->GetNumSetting("GuiOffsetX", 0)) ||
396 (curY != gCoreContext->GetNumSetting("GuiOffsetY", 0)) ||
397 (curW != gCoreContext->GetNumSetting("GuiWidth", 0)) ||
398 (curH != gCoreContext->GetNumSetting("GuiHeight", 0)))
399 reload = true;
400 }
401
402 delete wizard;
403 wizard = nullptr;
404 }
405
406 if (reload)
407 GetMythMainWindow()->JumpTo("Reload Theme");
408}
409
410static void startKeysSetup()
411{
413
414 auto *mythcontrols = new MythControls(mainStack, "mythcontrols");
415
416 if (mythcontrols->Create())
417 mainStack->AddScreen(mythcontrols);
418 else
419 delete mythcontrols;
420}
421
422static void startGuide(void)
423{
424 uint chanid = 0;
425 QString channum = gCoreContext->GetSetting("DefaultTVChannel");
426 QDateTime startTime;
427 GuideGrid::RunProgramGuide(chanid, channum, startTime, nullptr, false, true, -2);
428}
429
430static void startFinder(void)
431{
433}
434
435static void startSearchTitle(void)
436{
438 auto *pl = new ProgLister(mainStack, plTitleSearch, "", "");
439 if (pl->Create())
440 mainStack->AddScreen(pl);
441 else
442 delete pl;
443}
444
445static void startSearchKeyword(void)
446{
448 auto *pl = new ProgLister(mainStack, plKeywordSearch, "", "");
449 if (pl->Create())
450 mainStack->AddScreen(pl);
451 else
452 delete pl;
453}
454
455static void startSearchPeople(void)
456{
458 auto *pl = new ProgLister(mainStack, plPeopleSearch, "", "");
459 if (pl->Create())
460 mainStack->AddScreen(pl);
461 else
462 delete pl;
463}
464
465static void startSearchPower(void)
466{
468 auto *pl = new ProgLister(mainStack, plPowerSearch, "", "");
469 if (pl->Create())
470 mainStack->AddScreen(pl);
471 else
472 delete pl;
473}
474
475static void startSearchStored(void)
476{
478 auto *pl = new ProgLister(mainStack, plStoredSearch, "", "");
479 if (pl->Create())
480 mainStack->AddScreen(pl);
481 else
482 delete pl;
483}
484
485static void startSearchChannel(void)
486{
488 auto *pl = new ProgLister(mainStack, plChannel, "", "");
489 if (pl->Create())
490 mainStack->AddScreen(pl);
491 else
492 delete pl;
493}
494
495static void startSearchCategory(void)
496{
498 auto *pl = new ProgLister(mainStack, plCategory, "", "");
499 if (pl->Create())
500 mainStack->AddScreen(pl);
501 else
502 delete pl;
503}
504
505static void startSearchMovie(void)
506{
508 auto *pl = new ProgLister(mainStack, plMovies, "", "");
509 if (pl->Create())
510 mainStack->AddScreen(pl);
511 else
512 delete pl;
513}
514
515static void startSearchNew(void)
516{
518 auto *pl = new ProgLister(mainStack, plNewListings, "", "");
519 if (pl->Create())
520 mainStack->AddScreen(pl);
521 else
522 delete pl;
523}
524
525static void startSearchTime(void)
526{
528 auto *pl = new ProgLister(mainStack, plTime, "", "");
529 if (pl->Create())
530 mainStack->AddScreen(pl);
531 else
532 delete pl;
533}
534
535static void startManaged(void)
536{
538
539 auto *viewsched = new ViewScheduled(mainStack);
540
541 if (viewsched->Create())
542 mainStack->AddScreen(viewsched);
543 else
544 delete viewsched;
545}
546
548{
550
551 auto *progRecPrior = new ProgramRecPriority(mainStack, "ManageRecRules");
552
553 if (progRecPrior->Create())
554 mainStack->AddScreen(progRecPrior);
555 else
556 delete progRecPrior;
557}
558
560{
562
563 auto *chanRecPrior = new ChannelRecPriority(mainStack);
564
565 if (chanRecPrior->Create())
566 mainStack->AddScreen(chanRecPrior);
567 else
568 delete chanRecPrior;
569}
570
571static void startCustomPriority(void)
572{
574
575 auto *custom = new CustomPriority(mainStack);
576
577 if (custom->Create())
578 mainStack->AddScreen(custom);
579 else
580 delete custom;
581}
582
583static void startPlaybackWithGroup(const QString& recGroup = "")
584{
586
587 auto *pbb = new PlaybackBox(mainStack, "playbackbox");
588
589 if (pbb->Create())
590 {
591 if (!recGroup.isEmpty())
592 pbb->setInitialRecGroup(recGroup);
593
594 mainStack->AddScreen(pbb);
595 }
596 else
597 {
598 delete pbb;
599 }
600}
601
602static void startPlayback(void)
603{
605}
606
607static void startPrevious(void)
608{
610 auto *pl = new PrevRecordedList(mainStack);
611 if (pl->Create())
612 mainStack->AddScreen(pl);
613 else
614 delete pl;
615}
616
617static void startPreviousOld(void)
618{
620 auto *pl = new ProgLister(mainStack);
621 if (pl->Create())
622 mainStack->AddScreen(pl);
623 else
624 delete pl;
625}
626
627static void startCustomEdit(void)
628{
630 auto *custom = new CustomEdit(mainStack);
631
632 if (custom->Create())
633 mainStack->AddScreen(custom);
634 else
635 delete custom;
636}
637
638static void startManualSchedule(void)
639{
641
642 auto *mansched= new ManualSchedule(mainStack);
643
644 if (mansched->Create())
645 mainStack->AddScreen(mansched);
646 else
647 delete mansched;
648}
649
650static bool isLiveTVAvailable(void)
651{
653 return true;
654
655 QString msg = QCoreApplication::translate("(Common)", "All tuners are currently busy.");
656
657 if (TV::ConfiguredTunerCards() < 1)
658 msg = QCoreApplication::translate("(Common)", "There are no configured tuners.");
659
660 ShowOkPopup(msg);
661 return false;
662}
663
664static void startTVNormal(void)
665{
666 if (!isLiveTVAvailable())
667 return;
668
669 // Get the default channel keys (callsign(0) and channum(1)) and
670 // use them to generate the ordered list of channels.
671 QStringList keylist = gCoreContext->GetSettingOnHost(
672 "DefaultChanKeys", gCoreContext->GetHostName()).split("[]:[]");
673 while (keylist.size() < 2)
674 keylist << "";
675 uint dummy = 0;
677 0, // startIndex
678 0, // count
679 dummy, // totalAvailable
680 true, // ignoreHidden
683 0, // sourceID
684 0, // channelGroupID
685 true, // liveTVOnly
686 keylist[0], // callsign
687 keylist[1]); // channum
688
689 TV::StartTV(nullptr, kStartTVNoFlags, livetvchannels);
690}
691
692static void showStatus(void)
693{
695
696 auto *statusbox = new StatusBox(mainStack);
697
698 if (statusbox->Create())
699 mainStack->AddScreen(statusbox);
700 else
701 delete statusbox;
702}
703
704
705static void standbyScreen(void)
706{
708
709 auto *idlescreen = new IdleScreen(mainStack);
710
711 if (idlescreen->Create())
712 mainStack->AddScreen(idlescreen);
713 else
714 delete idlescreen;
715}
716
717static void RunVideoScreen(VideoDialog::DialogType type, bool fromJump = false)
718{
719 QString message = QCoreApplication::translate("(MythFrontendMain)",
720 "Loading videos ...");
721
722 MythScreenStack *popupStack =
723 GetMythMainWindow()->GetStack("popup stack");
724
725 auto *busyPopup = new MythUIBusyDialog(message, popupStack,
726 "mythvideobusydialog");
727
728 if (busyPopup->Create())
729 popupStack->AddScreen(busyPopup, false);
730
732
733 VideoDialog::VideoListPtr video_list;
734 if (fromJump)
735 {
738 if (!saved.isNull())
739 {
740 video_list = saved->GetSaved();
741 LOG(VB_GENERAL, LOG_INFO,
742 QString("Reusing saved video list because MythVideo was resumed"
743 " within %1ms").arg(VideoListDeathDelay::kDelayTimeMS.count()));
744 }
745 }
746
748 gCoreContext->GetNumSetting("mythvideo.db_group_type",
750
751 if (!video_list)
752 video_list = new VideoList;
753
754 auto *mythvideo =
755 new VideoDialog(mainStack, "mythvideo", video_list, type, browse);
756
757 if (mythvideo->Create())
758 {
759 busyPopup->Close();
760 mainStack->AddScreen(mythvideo);
761 }
762 else
763 {
764 busyPopup->Close();
765 }
766}
767
773
774static void RunGallery()
775{
777 auto *galleryView = new GalleryThumbView(mainStack, "galleryview");
778 if (galleryView->Create())
779 {
780 mainStack->AddScreen(galleryView);
781 galleryView->Start();
782 }
783 else
784 {
785 delete galleryView;
786 }
787}
788
789static void playDisc()
790{
791 // Check for Bluray
792 LOG(VB_MEDIA, LOG_DEBUG, "Checking for BluRay medium");
793 const QString bluray_mountpoint =
794 gCoreContext->GetSetting("BluRayMountpoint", "/media/cdrom");
795 QDir bdtest(bluray_mountpoint + "/BDMV");
796 const bool isBD = (bdtest.exists() || MythCDROM::inspectImage(bluray_mountpoint) == MythCDROM::kBluray);
797 if (isBD)
798 {
799 GetMythUI()->AddCurrentLocation("playdisc");
800
801 QString filename = QString("bd:/%1").arg(bluray_mountpoint);
802
803 GetMythMainWindow()->HandleMedia("Internal", filename, "", "", "", "",
804 0, 0, "", 0min, "", "", true);
805
807 return;
808 }
809
811 if (!mediaMonitor)
812 {
813 LOG(VB_MEDIA, LOG_ERR, "Could not access media monitor");
814 return;
815 }
816
817 // Check for DVD
818 LOG(VB_MEDIA, LOG_DEBUG, "Checking for DVD medium");
819 const bool isDVD = mediaMonitor->IsActive()
820 ? !mediaMonitor->GetMedias(MEDIATYPE_DVD).isEmpty()
822 if (isDVD)
823 {
824 QString dvd_device = MediaMonitor::defaultDVDdevice();
825
826 if (dvd_device.isEmpty())
827 return; // User cancelled in the Popup
828
829 GetMythUI()->AddCurrentLocation("playdisc");
830
831 // Get the command string to play a DVD
832 QString command_string =
833 gCoreContext->GetSetting("mythdvd.DVDPlayerCommand");
834 if ((command_string.indexOf("internal", 0, Qt::CaseInsensitive) > -1) ||
835 (command_string.length() < 1))
836 {
837#ifdef Q_OS_DARWIN
838 // Convert a BSD 'leaf' name into a raw device path
839 QString filename = "dvd://dev/r"; // e.g. 'dvd://dev/rdisk2'
840#elif defined(_WIN32)
841 QString filename = "dvd:"; // e.g. 'dvd:E\\'
842#else
843 QString filename = "dvd:/"; // e.g. 'dvd://dev/sda'
844#endif
845 filename += dvd_device;
846
847 command_string = "Internal";
848 GetMythMainWindow()->HandleMedia(command_string, filename, "", "",
849 "", "", 0, 0, "", 0min, "", "", true);
851
852 return;
853 }
854
855 if (command_string.contains("%d"))
856 {
857 //
858 // Need to do device substitution
859 //
860 command_string = command_string.replace("%d", dvd_device);
861 }
864 myth_system(command_string);
867 if (GetMythMainWindow())
868 {
869 GetMythMainWindow()->raise();
870 GetMythMainWindow()->activateWindow();
871 }
873 return;
874 }
875
876 // Check for Audio CD
877 LOG(VB_MEDIA, LOG_DEBUG, "Checking for audio CD medium");
878 if (mediaMonitor->IsActive())
879 {
880 auto audioMedia = mediaMonitor->GetMedias(MEDIATYPE_AUDIO | MEDIATYPE_MIXED);
881 if (!audioMedia.isEmpty())
882 {
883 for (auto *medium : std::as_const(audioMedia))
884 {
885 if (medium->isUsable()) {
886 LOG(VB_MEDIA, LOG_DEBUG, QString("Found usable audio/mixed device %1").arg(medium->getDevicePath()));
887 mediaMonitor->JumpToMediaHandler(medium, true);
888 return;
889 }
890 }
891 }
892 }
893}
894
898static void handleDVDMedia(MythMediaDevice *dvd, bool /*forcePlayback*/)
899{
900 if (!dvd)
901 return;
902
903 if (!dvd->isUsable()) // This isn't infallible, on some drives both a mount and libudf fail
904 return;
905
906 switch (gCoreContext->GetNumSetting("DVDOnInsertDVD", 1))
907 {
908 case 0 : // Do nothing
909 case 1 : // Display menu (mythdvd)*/
910 break;
911 case 2 : // play DVD or Blu-ray
912 playDisc();
913 break;
914 default:
915 LOG(VB_GENERAL, LOG_ERR,
916 "mythdvd main.o: handleMedia() does not know what to do");
917 }
918}
919
920static void handleGalleryMedia(MythMediaDevice *dev, bool forcePlayback)
921{
922 // Only handle events for media that are newly mounted
923 if (!dev || (dev->getStatus() != MEDIASTAT_MOUNTED
924 && dev->getStatus() != MEDIASTAT_USEABLE))
925 return;
926
927 // Check if gallery is already running
928 QVector<MythScreenType*> screens;
930
931
932 for (const auto *screen : std::as_const(screens))
933 {
934 if (qobject_cast<const GalleryThumbView*>(screen))
935 {
936 // Running gallery will receive this event later
937 LOG(VB_MEDIA, LOG_INFO, "Main: Ignoring new gallery media - already running");
938 return;
939 }
940 }
941
942 if (forcePlayback || gCoreContext->GetBoolSetting("GalleryAutoLoad", false))
943 {
944 LOG(VB_GUI, LOG_INFO, "Main: Autostarting Gallery for new media");
946 }
947 else
948 {
949 LOG(VB_MEDIA, LOG_INFO, "Main: Ignoring new gallery media - autorun not set");
950 }
951}
952
953static void TVMenuCallback(void * /* data */, QString &selection)
954{
955 QString sel = selection.toLower();
956
957 if (sel.startsWith("settings ") || sel == "video_settings_general")
958 {
959 if (!g_settingsHelper)
961
963 }
964
965 if (sel == "tv_watch_live")
967 else if (sel.startsWith("tv_watch_recording"))
968 {
969 // use selection here because its case is untouched
970 if ((selection.length() > 19) && (selection.mid(18, 1) == " "))
971 startPlaybackWithGroup(selection.mid(19));
972 else
974 }
975 else if (sel == "tv_schedule")
976 {
977 startGuide();
978 }
979 else if (sel == "tv_manualschedule")
980 {
982 }
983 else if (sel == "tv_custom_record")
984 {
986 }
987 else if (sel == "tv_fix_conflicts")
988 {
989 startManaged();
990 }
991 else if (sel == "tv_manage_recording_rules")
992 {
994 }
995 else if (sel == "tv_progfind")
996 {
997 startFinder();
998 }
999 else if (sel == "tv_search_title")
1000 {
1002 }
1003 else if (sel == "tv_search_keyword")
1004 {
1006 }
1007 else if (sel == "tv_search_people")
1008 {
1010 }
1011 else if (sel == "tv_search_power")
1012 {
1014 }
1015 else if (sel == "tv_search_stored")
1016 {
1018 }
1019 else if (sel == "tv_search_channel")
1020 {
1022 }
1023 else if (sel == "tv_search_category")
1024 {
1026 }
1027 else if (sel == "tv_search_movie")
1028 {
1030 }
1031 else if (sel == "tv_search_new")
1032 {
1034 }
1035 else if (sel == "tv_search_time")
1036 {
1038 }
1039 else if (sel == "tv_previous")
1040 {
1041 startPrevious();
1042 }
1043 else if (sel == "tv_previous_old")
1044 {
1046 }
1047 else if (sel == "settings appearance")
1048 {
1050 auto *ssd = new StandardSettingDialog(mainStack, "videogeneralsettings",
1051 new AppearanceSettings());
1052
1053 if (ssd->Create())
1054 {
1055 mainStack->AddScreen(ssd);
1056 }
1057 else
1058 {
1059 delete ssd;
1060 }
1061 }
1062 else if (sel == "settings themechooser")
1063 {
1065 auto *tp = new ThemeChooser(mainStack);
1066
1067 if (tp->Create())
1068 mainStack->AddScreen(tp);
1069 else
1070 delete tp;
1071 }
1072 else if (sel == "settings setupwizard")
1073 {
1075 auto *sw = new GeneralSetupWizard(mainStack, "setupwizard");
1076
1077 if (sw->Create())
1078 mainStack->AddScreen(sw);
1079 else
1080 delete sw;
1081 }
1082 else if (sel == "settings grabbers")
1083 {
1085 auto *gs = new GrabberSettings(mainStack, "grabbersettings");
1086
1087 if (gs->Create())
1088 mainStack->AddScreen(gs);
1089 else
1090 delete gs;
1091 }
1092 else if (sel == "screensetupwizard")
1093 {
1095 }
1096 else if (sel == "setup_keys")
1097 {
1099 }
1100 else if (sel == "settings playgroup")
1101 {
1103 auto *ssd = new StandardSettingDialog(mainStack, "playbackgroupsetting",
1104 new PlayGroupEditor());
1105
1106 if (ssd->Create())
1107 {
1108 mainStack->AddScreen(ssd);
1109 }
1110 else
1111 {
1112 delete ssd;
1113 }
1114 }
1115 else if (sel == "settings general")
1116 {
1118 auto *ssd = new StandardSettingDialog(mainStack, "videogeneralsettings",
1119 new GeneralSettings());
1120
1121 if (ssd->Create())
1122 {
1123 mainStack->AddScreen(ssd);
1124 }
1125 else
1126 {
1127 delete ssd;
1128 }
1129 }
1130 else if (sel == "settings audiogeneral")
1131 {
1134 new AudioConfigScreen(mainStack, "audiogeneralsettings",
1135 new AudioConfigSettings());
1136
1137 if (ssd->Create())
1138 {
1139 mainStack->AddScreen(ssd);
1140 }
1141 else
1142 {
1143 delete ssd;
1144 }
1145 }
1146 else if (sel == "settings maingeneral")
1147 {
1149 auto *ssd = new StandardSettingDialog(mainStack, "maingeneralsettings",
1150 new MainGeneralSettings());
1151
1152 if (ssd->Create())
1153 {
1154 mainStack->AddScreen(ssd);
1155 }
1156 else
1157 {
1158 delete ssd;
1159 }
1160 }
1161 else if (sel == "settings playback")
1162 {
1165 new PlaybackSettingsDialog(mainStack);
1166
1167 if (ssd->Create())
1168 {
1169 mainStack->AddScreen(ssd);
1170 }
1171 else
1172 {
1173 delete ssd;
1174 }
1175 }
1176 else if (sel == "settings osd")
1177 {
1179 auto *ssd = new StandardSettingDialog(mainStack, "osdsettings",
1180 new OSDSettings());
1181
1182 if (ssd->Create())
1183 {
1184 mainStack->AddScreen(ssd);
1185 }
1186 else
1187 {
1188 delete ssd;
1189 }
1190 }
1191 else if (sel == "settings epg")
1192 {
1194 auto *ssd = new StandardSettingDialog(mainStack, "epgsettings",
1195 new EPGSettings());
1196
1197 if (ssd->Create())
1198 {
1199 mainStack->AddScreen(ssd);
1200 }
1201 else
1202 {
1203 delete ssd;
1204 }
1205 }
1206 else if (sel == "settings channelgroups")
1207 {
1209 auto *ssd = new StandardSettingDialog(mainStack, "channelgroupssettings",
1210 new ChannelGroupsSetting());
1211
1212 if (ssd->Create())
1213 {
1214 mainStack->AddScreen(ssd);
1215 }
1216 else
1217 {
1218 delete ssd;
1219 }
1220 }
1221 else if (sel == "settings generalrecpriorities")
1222 {
1224 auto *ssd = new StandardSettingDialog(mainStack,
1225 "generalrecprioritiessettings",
1227
1228 if (ssd->Create())
1229 {
1230 mainStack->AddScreen(ssd);
1231 }
1232 else
1233 {
1234 delete ssd;
1235 }
1236 }
1237 else if (sel == "settings channelrecpriorities")
1238 {
1240 }
1241 else if (sel == "settings custompriority")
1242 {
1244 }
1245 else if (sel == "system_events")
1246 {
1248
1249 auto *msee = new MythSystemEventEditor(mainStack, "System Event Editor");
1250
1251 if (msee->Create())
1252 mainStack->AddScreen(msee);
1253 else
1254 delete msee;
1255 }
1256 else if (sel == "video_settings_general")
1257 {
1258 RunSettingsCompletion::Create(gCoreContext->
1259 GetBoolSetting("VideoAggressivePC", false));
1260 }
1261 else if (sel == "video_settings_player")
1262 {
1264
1265 auto *ps = new PlayerSettings(mainStack, "player settings");
1266
1267 if (ps->Create())
1268 mainStack->AddScreen(ps);
1269 else
1270 delete ps;
1271 }
1272 else if (sel == "video_settings_metadata")
1273 {
1275
1276 auto *ms = new MetadataSettings(mainStack, "metadata settings");
1277
1278 if (ms->Create())
1279 mainStack->AddScreen(ms);
1280 else
1281 delete ms;
1282 }
1283 else if (sel == "video_settings_associations")
1284 {
1286
1287 auto *fa = new FileAssocDialog(mainStack, "fa dialog");
1288
1289 if (fa->Create())
1290 mainStack->AddScreen(fa);
1291 }
1292 else if (sel == "manager")
1293 {
1295 }
1296 else if (sel == "browser")
1297 {
1299 }
1300 else if (sel == "listing")
1301 {
1303 }
1304 else if (sel == "gallery")
1305 {
1307 }
1308 else if (sel == "disc_play")
1309 {
1310 playDisc();
1311 }
1312 else if (sel == "tv_status")
1313 {
1314 showStatus();
1315 }
1316 else if (sel == "exiting_app_prompt")
1317 {
1318 handleExit(true);
1319 }
1320 else if (sel == "exiting_app")
1321 {
1322 handleExit(false);
1323 }
1324 else if (sel == "standby_mode")
1325 {
1326 standbyScreen();
1327 }
1328 else if (sel == "exiting_menu")
1329 {
1330 //ignore
1331 }
1332 else
1333 {
1334 LOG(VB_GENERAL, LOG_ERR, "Unknown menu action: " + selection);
1335 }
1336
1337 if (sel.startsWith("settings ") || sel == "video_settings_general")
1338 {
1339 if (g_settingsHelper)
1340 {
1341 QObject::connect(GetMythMainWindow()->GetMainStack()->GetTopScreen(),
1344 }
1345 }
1346}
1347
1348static void handleExit(bool prompt)
1349{
1350 if (prompt)
1351 {
1352 auto * prompter = new ExitPrompter();
1353 prompter->HandleExit();
1354 }
1355 else
1356 {
1358 }
1359}
1360
1361static bool RunMenu(const QString& themedir, const QString& themename)
1362{
1363 QByteArray tmp = themedir.toLocal8Bit();
1364 g_menu = new MythThemedMenu(QString(tmp.constData()), "mainmenu.xml",
1365 GetMythMainWindow()->GetMainStack(), "mainmenu");
1366
1367 if (g_menu->foundTheme())
1368 {
1369 LOG(VB_GENERAL, LOG_NOTICE, QString("Found mainmenu.xml for theme '%1'")
1370 .arg(themename));
1373 return true;
1374 }
1375
1376 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find mainmenu.xml for theme '%1'")
1377 .arg(themename));
1378 delete g_menu;
1379 g_menu = nullptr;
1380 return false;
1381}
1382
1383// If any settings are missing from the database, this will write
1384// the default values
1385static void WriteDefaults()
1386{
1388 ps.Load();
1389 ps.Save();
1390 OSDSettings os;
1391 os.Load();
1392 os.Save();
1393 GeneralSettings gs;
1394 gs.Load();
1395 gs.Save();
1396 EPGSettings es;
1397 es.Load();
1398 es.Save();
1400 as.Load();
1401 as.Save();
1403 mgs.Load();
1404 mgs.Save();
1406 grs.Load();
1407 grs.Save();
1409 vgs.Load();
1410 vgs.Save();
1411 //TODo Playback group not loaded?
1412 //TODo Channel group not loaded?
1413}
1414
1415static int internal_play_media(const QString &mrl, const QString &plot,
1416 const QString &title, const QString &subtitle,
1417 const QString &director, int season, int episode,
1418 const QString &inetref, std::chrono::minutes lenMins,
1419 const QString &year,
1420 const QString &id, const bool useBookmark)
1421{
1422 int res = -1;
1423
1424 QFile checkFile(mrl);
1425 if ((!checkFile.exists() && !mrl.startsWith("dvd:")
1426 && !mrl.startsWith("bd:")
1427 && !mrl.startsWith("myth:")
1428 && !mrl.startsWith("http://")
1429 && !mrl.startsWith("https://")))
1430 {
1431 QString errorText = QCoreApplication::translate("(MythFrontendMain)",
1432 "Failed to open \n '%1' in %2 \n"
1433 "Check if the video exists")
1434 .arg(mrl.section('/', -1),
1435 mrl.section('/', 0, -2));
1436
1437 ShowOkPopup(errorText);
1438 return res;
1439 }
1440
1441 auto *pginfo = new ProgramInfo(
1442 mrl, plot, title, QString(), subtitle, QString(),
1443 director, season, episode, inetref, lenMins,
1444 (year.toUInt()) ? year.toUInt() : 1900, id);
1445
1446 pginfo->SetProgramInfoType(pginfo->DiscoverProgramInfoType());
1447
1448 bool bookmarkPresent = false;
1449 bool lastPlayPresent = false;
1450
1451 if (pginfo->IsVideoDVD())
1452 {
1453 auto *dvd = new MythDVDInfo(pginfo->GetPlaybackURL());
1454 if (dvd->IsValid())
1455 {
1456 QString name;
1457 QString serialid;
1458 if (dvd->GetNameAndSerialNum(name, serialid))
1459 {
1460 QStringList fields = pginfo->QueryDVDBookmark(serialid);
1461 bookmarkPresent = (fields.count() > 0);
1462 }
1463 }
1464 else
1465 {
1466 ShowNotificationError(QCoreApplication::translate("(MythFrontendMain)",
1467 "DVD Failure"),
1468 sLocation,
1469 dvd->GetLastError());
1470 delete dvd;
1471 delete pginfo;
1472 return res;
1473 }
1474 delete dvd;
1475 }
1476 else if (pginfo->IsVideoBD())
1477 {
1478 MythBDInfo bd(pginfo->GetPlaybackURL());
1479 if (bd.IsValid())
1480 {
1481 QString name;
1482 QString serialid;
1483 if (bd.GetNameAndSerialNum(name, serialid))
1484 {
1485 QStringList fields = pginfo->QueryBDBookmark(serialid);
1486 bookmarkPresent = (fields.count() > 0);
1487 }
1488 }
1489 else
1490 {
1491 ShowNotificationError(QCoreApplication::translate("(MythFrontendMain)",
1492 "BD Failure"),
1493 sLocation,
1494 bd.GetLastError());
1495 delete pginfo;
1496 return res;
1497 }
1498 }
1499 else if (useBookmark && pginfo->IsVideo())
1500 {
1501 pginfo->SetIgnoreLastPlayPos(false);
1502 pginfo->SetIgnoreBookmark(false);
1503 bookmarkPresent = pginfo->QueryBookmark() > 0;
1504 lastPlayPresent = pginfo->QueryLastPlayPos() > 0;
1505 }
1506
1507 if (useBookmark && (bookmarkPresent || lastPlayPresent))
1508 {
1510 auto *bookmarkdialog = new BookmarkDialog(pginfo, mainStack,
1511 bookmarkPresent,
1512 lastPlayPresent);
1513 if (!bookmarkdialog->Create())
1514 {
1515 delete bookmarkdialog;
1516 delete pginfo;
1517 return res;
1518 }
1519 }
1520 else
1521 {
1523
1524 res = 0;
1525
1526 delete pginfo;
1527 }
1528
1529 return res;
1530}
1531
1532static void gotoMainMenu(void)
1533{
1534 // Reset the selected button to the first item.
1535 auto *lmenu = qobject_cast<MythThemedMenuState *>
1536 (GetMythMainWindow()->GetMainStack()->GetTopScreen());
1537 if (lmenu)
1538 lmenu->m_buttonList->SetItemCurrent(0);
1539}
1540
1541// If the theme specified in the DB is somehow broken, try a standard one:
1542//
1543static bool resetTheme(QString themedir, const QString &badtheme)
1544{
1545 QString themename = DEFAULT_UI_THEME;
1546
1547 if (badtheme == DEFAULT_UI_THEME)
1548 themename = FALLBACK_UI_THEME;
1549
1550 LOG(VB_GENERAL, LOG_WARNING, QString("Overriding broken theme '%1' with '%2'")
1551 .arg(badtheme, themename));
1552
1553 gCoreContext->OverrideSettingForSession("Theme", themename);
1554 themedir = GetMythUI()->FindThemeDir(themename);
1555
1559
1560 return RunMenu(themedir, themename);
1561}
1562
1563static int reloadTheme(void)
1564{
1565#ifdef Q_OS_ANDROID
1566 // jni code to launch the application again
1567 // reinitializing the main windows causes a segfault
1568 // with android
1569
1570#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1571 auto activity = QtAndroid::androidActivity();
1572#else
1573 QJniObject activity = QNativeInterface::QAndroidApplication::context();
1574#endif
1575 auto packageManager = activity.callObjectMethod
1576 ( "getPackageManager",
1577 "()Landroid/content/pm/PackageManager;" );
1578
1579 auto activityIntent = packageManager.callObjectMethod
1580 ( "getLaunchIntentForPackage",
1581 "(Ljava/lang/String;)Landroid/content/Intent;",
1582 activity.callObjectMethod("getPackageName",
1583 "()Ljava/lang/String;").object() );
1584
1585 auto pendingIntent = QAndroidJniObject::callStaticObjectMethod
1586 ( "android/app/PendingIntent",
1587 "getActivity",
1588 "(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;",
1589 activity.object(),
1590 0,
1591 activityIntent.object(),
1592 QAndroidJniObject::getStaticField<jint>("android/content/Intent",
1593 "FLAG_ACTIVITY_CLEAR_TOP") );
1594
1595 auto alarmManager = activity.callObjectMethod
1596 ( "getSystemService",
1597 "(Ljava/lang/String;)Ljava/lang/Object;",
1598 QAndroidJniObject::getStaticObjectField("android/content/Context",
1599 "ALARM_SERVICE",
1600 "Ljava/lang/String;").object() );
1601
1602 alarmManager.callMethod<void>
1603 ( "set",
1604 "(IJLandroid/app/PendingIntent;)V",
1605 QAndroidJniObject::getStaticField<jint>("android/app/AlarmManager", "RTC"),
1606 jlong(QDateTime::currentMSecsSinceEpoch() + 100),
1607 pendingIntent.object() );
1608
1609 qApp->quit();
1610 // QString title = QObject::tr("Your change will take effect the next time "
1611 // "mythfrontend is started.");
1612 // MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack"); MythConfirmationDialog *okPopup =
1613 // new MythConfirmationDialog(popupStack, title, false);
1614 // if (okPopup->Create())
1615 // popupStack->AddScreen(okPopup);
1616 return 0;
1617#else
1619 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
1620 QString themedir = GetMythUI()->FindThemeDir(themename);
1621 if (themedir.isEmpty())
1622 {
1623 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'").arg(themename));
1624 return GENERIC_EXIT_NO_THEME;
1625 }
1626
1630 if (g_menu)
1631 g_menu->Close();
1634 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
1635 return GENERIC_EXIT_NO_THEME;
1636
1637 LCD::SetupLCD();
1638 if (LCD *lcd = LCD::Get())
1639 {
1640 lcd->setupLEDs(RemoteGetRecordingMask);
1641 lcd->resetServer();
1642 }
1643
1644 return 0;
1645#endif
1646}
1647
1648static void reloadTheme_void(void)
1649{
1650 int err = reloadTheme();
1651 if (err)
1652 exit(err);
1653}
1654
1655static void setDebugShowBorders(void)
1656{
1658 MythPainter* painter = window->GetPainter();
1659 painter->SetDebugMode(!painter->ShowBorders(), painter->ShowTypeNames());
1660 if (window->GetMainStack()->GetTopScreen())
1661 window->GetMainStack()->GetTopScreen()->SetRedraw();
1662}
1663
1664static void setDebugShowNames(void)
1665{
1667 MythPainter* painter = window->GetPainter();
1668 painter->SetDebugMode(painter->ShowBorders(), !painter->ShowTypeNames());
1669 if (window->GetMainStack()->GetTopScreen())
1670 window->GetMainStack()->GetTopScreen()->SetRedraw();
1671}
1672
1673static void InitJumpPoints(void)
1674{
1675 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Reload Theme"),
1676 "", "", reloadTheme_void);
1677 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Main Menu"),
1678 "", "", gotoMainMenu);
1679 REG_JUMPLOC(QT_TRANSLATE_NOOP("MythControls", "Program Guide"),
1680 "", "", startGuide, "GUIDE");
1681 REG_JUMPLOC(QT_TRANSLATE_NOOP("MythControls", "Program Finder"),
1682 "", "", startFinder, "FINDER");
1683 //REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Search Listings"),
1684 // "", "", startSearch);
1685 REG_JUMPLOC(QT_TRANSLATE_NOOP("MythControls", "Manage Recordings / "
1686 "Fix Conflicts"), "", "", startManaged, "VIEWSCHEDULED");
1687 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Manage Recording Rules"),
1689 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Channel Recording "
1690 "Priorities"), "", "", startChannelRecPriorities);
1691 REG_JUMPLOC(QT_TRANSLATE_NOOP("MythControls", "TV Recording Playback"),
1692 "", "", startPlayback, "JUMPREC");
1693 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Live TV"),
1694 "", "", startTVNormal);
1695 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Status Screen"),
1696 "", "", showStatus);
1697 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Previously Recorded"),
1698 "", "", startPrevious);
1699
1700 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Standby Mode"),
1701 "", "", standbyScreen);
1702
1703 // Video
1704
1705 REG_JUMP(JUMP_VIDEO_DEFAULT, QT_TRANSLATE_NOOP("MythControls",
1706 "The Video Default View"), "", jumpScreenVideoDefault);
1707 REG_JUMP(JUMP_VIDEO_MANAGER, QT_TRANSLATE_NOOP("MythControls",
1708 "The Video Manager"), "", jumpScreenVideoManager);
1709 REG_JUMP(JUMP_VIDEO_BROWSER, QT_TRANSLATE_NOOP("MythControls",
1710 "The Video Browser"), "", jumpScreenVideoBrowser);
1711 REG_JUMP(JUMP_VIDEO_TREE, QT_TRANSLATE_NOOP("MythControls",
1712 "The Video Listings"), "", jumpScreenVideoTree);
1713 REG_JUMP(JUMP_VIDEO_GALLERY, QT_TRANSLATE_NOOP("MythControls",
1714 "The Video Gallery"), "", jumpScreenVideoGallery);
1715 REG_JUMP("Play Disc", QT_TRANSLATE_NOOP("MythControls",
1716 "Play an Optical Disc"), "", playDisc);
1717
1718 // Gallery
1719
1720 REG_JUMP(JUMP_GALLERY_DEFAULT, QT_TRANSLATE_NOOP("MythControls",
1721 "Image Gallery"), "", RunGallery);
1722
1723 REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Toggle Show Widget Borders"),
1724 "", "", setDebugShowBorders, false);
1725 REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Toggle Show Widget Names"),
1726 "", "", setDebugShowNames, false);
1727 REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Reset All Keys"),
1728 QT_TRANSLATE_NOOP("MythControls", "Reset all keys to defaults"),
1729 "", resetAllKeys, false);
1730}
1731
1732static void ReloadJumpPoints(void)
1733{
1734 MythMainWindow *mainWindow = GetMythMainWindow();
1735 mainWindow->ClearAllJumps();
1737}
1738
1739static void InitKeys(void)
1740{
1741 REG_KEY("Video","PLAYALT", QT_TRANSLATE_NOOP("MythControls",
1742 "Play selected item in alternate player"), "ALT+P");
1743 REG_KEY("Video","FILTER", QT_TRANSLATE_NOOP("MythControls",
1744 "Open video filter dialog"), "F");
1745 REG_KEY("Video","INCPARENT", QT_TRANSLATE_NOOP("MythControls",
1746 "Increase Parental Level"), "],},F11");
1747 REG_KEY("Video","DECPARENT", QT_TRANSLATE_NOOP("MythControls",
1748 "Decrease Parental Level"), "[,{,F10");
1749 REG_KEY("Video","INCSEARCH", QT_TRANSLATE_NOOP("MythControls",
1750 "Show Incremental Search Dialog"), "Ctrl+S,Search");
1751 REG_KEY("Video","DOWNLOADDATA", QT_TRANSLATE_NOOP("MythControls",
1752 "Download metadata for current item"), "W");
1753 REG_KEY("Video","ITEMDETAIL", QT_TRANSLATE_NOOP("MythControls",
1754 "Display Item Detail Popup"), "");
1755
1756 // Gallery keybindings
1757 REG_KEY("Images", "PLAY", QT_TRANSLATE_NOOP("MythControls",
1758 "Start/Stop Slideshow"), "P,Media Play");
1759 REG_KEY("Images", "RECURSIVESHOW", QT_TRANSLATE_NOOP("MythControls",
1760 "Start Recursive Slideshow"), "R");
1761 REG_KEY("Images", "ROTRIGHT", QT_TRANSLATE_NOOP("MythControls",
1762 "Rotate image right 90 degrees"), "],3");
1763 REG_KEY("Images", "ROTLEFT", QT_TRANSLATE_NOOP("MythControls",
1764 "Rotate image left 90 degrees"), "[,1");
1765 REG_KEY("Images", "FLIPHORIZONTAL", QT_TRANSLATE_NOOP("MythControls",
1766 "Flip image horizontally"), "");
1767 REG_KEY("Images", "FLIPVERTICAL", QT_TRANSLATE_NOOP("MythControls",
1768 "Flip image vertically"), "");
1769 REG_KEY("Images", "ZOOMOUT", QT_TRANSLATE_NOOP("MythControls",
1770 "Zoom image out"), "7,<,Ctrl+B,Media Rewind");
1771 REG_KEY("Images", "ZOOMIN", QT_TRANSLATE_NOOP("MythControls",
1772 "Zoom image in"), "9,>,Ctrl+F,Media Fast Forward");
1773 REG_KEY("Images", "FULLSIZE", QT_TRANSLATE_NOOP("MythControls",
1774 "Full-size (un-zoom) image"), "0");
1775 REG_KEY("Images", "MARK", QT_TRANSLATE_NOOP("MythControls",
1776 "Mark image"), "T");
1777 REG_KEY("Images", "SCROLLUP", QT_TRANSLATE_NOOP("MythControls",
1778 "Scroll image up"), "2");
1779 REG_KEY("Images", "SCROLLLEFT", QT_TRANSLATE_NOOP("MythControls",
1780 "Scroll image left"), "4");
1781 REG_KEY("Images", "SCROLLRIGHT", QT_TRANSLATE_NOOP("MythControls",
1782 "Scroll image right"), "6");
1783 REG_KEY("Images", "SCROLLDOWN", QT_TRANSLATE_NOOP("MythControls",
1784 "Scroll image down"), "8");
1785 REG_KEY("Images", "RECENTER", QT_TRANSLATE_NOOP("MythControls",
1786 "Recenter image"), "5");
1787 REG_KEY("Images", "COVER", QT_TRANSLATE_NOOP("MythControls",
1788 "Set or clear cover image"), "C");
1789}
1790
1791static void ReloadKeys(void)
1792{
1793 MythMainWindow* mainwindow = GetMythMainWindow();
1794 if (mainwindow)
1795 mainwindow->ClearKeyContext("Video");
1796 InitKeys();
1797 if (mainwindow)
1798 mainwindow->ReloadKeys();
1799}
1800
1801static void SetFuncPtrs(void)
1802{
1803 TV::SetFuncPtr("playbackbox", (void *)PlaybackBox::RunPlaybackBox);
1804 TV::SetFuncPtr("viewscheduled", (void *)ViewScheduled::RunViewScheduled);
1805 TV::SetFuncPtr("programguide", (void *)GuideGrid::RunProgramGuide);
1806 TV::SetFuncPtr("programlist", (void *)ProgLister::RunProgramList);
1807 TV::SetFuncPtr("scheduleeditor", (void *)ScheduleEditor::RunScheduleEditor);
1808 TV::SetFuncPtr("programfinder", (void *)RunProgramFinder);
1809}
1810
1814static void clearAllKeys(void)
1815{
1817
1818 query.prepare("DELETE FROM keybindings "
1819 "WHERE hostname = :HOSTNAME;");
1820 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1821 if (!query.exec())
1822 MythDB::DBError("Deleting keybindings", query);
1823 query.prepare("DELETE FROM jumppoints "
1824 "WHERE hostname = :HOSTNAME;");
1825 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1826 if (!query.exec())
1827 MythDB::DBError("Deleting jumppoints", query);
1828}
1829
1833static void resetAllKeys(void)
1834{
1835 clearAllKeys();
1836 // Reload MythMainWindow bindings
1838 // Reload Jump Points
1840 // Reload mythfrontend and TV bindings
1841 ReloadKeys();
1842}
1843
1845{
1846 REG_MEDIAPLAYER("Internal", QT_TRANSLATE_NOOP("MythControls",
1847 "MythTV's native media player."), internal_play_media);
1848 REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
1849 "MythDVD DVD Media Handler"), "", handleDVDMedia,
1850 MEDIATYPE_DVD, QString());
1851 REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
1852 "MythImage Media Handler 1/2"), "", handleGalleryMedia,
1853 MEDIATYPE_DATA | MEDIATYPE_MIXED, QString());
1854
1855 QStringList extensions(ImageAdapterBase::SupportedImages()
1857
1858 REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
1859 "MythImage Media Handler 2/2"), "", handleGalleryMedia,
1860 MEDIATYPE_MGALLERY | MEDIATYPE_MVIDEO, extensions.join(","));
1861 return 0;
1862}
1863
1865{
1867
1868 query.prepare("DELETE FROM inuseprograms "
1869 "WHERE hostname = :HOSTNAME and recusage = 'player' ;");
1870 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1871 if (!query.exec())
1872 MythDB::DBError("CleanupMyOldInUsePrograms", query);
1873}
1874
1875static bool WasAutomaticStart(void)
1876{
1877 bool autoStart = false;
1878
1879 // Is backend running?
1880 //
1882 {
1883 QDateTime startupTime = QDateTime();
1884
1885 if( gCoreContext->IsMasterHost() )
1886 {
1887 QString s = gCoreContext->GetSetting("MythShutdownWakeupTime", "");
1888 if (!s.isEmpty())
1889 startupTime = MythDate::fromString(s);
1890
1891 // if we don't have a valid startup time assume we were started manually
1892 if (startupTime.isValid())
1893 {
1894 auto startupSecs = gCoreContext->GetDurSetting<std::chrono::seconds>("StartupSecsBeforeRecording");
1895 startupSecs = std::max(startupSecs, 15 * 60s);
1896 // If we started within 'StartupSecsBeforeRecording' OR 15 minutes
1897 // of the saved wakeup time assume we either started automatically
1898 // to record, to obtain guide data or or for a
1899 // daily wakeup/shutdown period
1900 if (abs(MythDate::secsInPast(startupTime)) < startupSecs)
1901 {
1902 LOG(VB_GENERAL, LOG_INFO,
1903 "Close to auto-start time, AUTO-Startup assumed");
1904
1905 QString str = gCoreContext->GetSetting("MythFillSuggestedRunTime");
1906 QDateTime guideRunTime = MythDate::fromString(str);
1907 if (MythDate::secsInPast(guideRunTime) < startupSecs)
1908 {
1909 LOG(VB_GENERAL, LOG_INFO,
1910 "Close to MythFillDB suggested run time, AUTO-Startup to fetch guide data?");
1911 }
1912 autoStart = true;
1913 }
1914 else
1915 {
1916 LOG(VB_GENERAL, LOG_DEBUG,
1917 "NOT close to auto-start time, USER-initiated startup assumed");
1918 }
1919 }
1920 }
1921 else
1922 {
1923 QString wakeupCmd = gCoreContext->GetSetting("WakeUpCommand");
1924
1925 // A slave backend that has no wakeup command cannot be woken
1926 // automatically so can be ignored.
1927 if (!wakeupCmd.isEmpty())
1928 {
1929 ProgramList progList;
1930 bool bConflicts = false;
1931 QDateTime nextRecordingStart;
1932
1933 if (LoadFromScheduler(progList, bConflicts))
1934 {
1935 // Find the first recording to be recorded
1936 // on this machine
1937 QString hostname = gCoreContext->GetHostName();
1938 for (auto *prog : progList)
1939 {
1940 if ((prog->GetRecordingStatus() == RecStatus::WillRecord ||
1941 prog->GetRecordingStatus() == RecStatus::Pending) &&
1942 (prog->GetHostname() == hostname) &&
1943 (nextRecordingStart.isNull() ||
1944 nextRecordingStart > prog->GetRecordingStartTime()))
1945 {
1946 nextRecordingStart = prog->GetRecordingStartTime();
1947 }
1948 }
1949
1950 if (!nextRecordingStart.isNull() &&
1951 (abs(MythDate::secsInPast(nextRecordingStart)) < 4min))
1952 {
1953 LOG(VB_GENERAL, LOG_INFO,
1954 "Close to start time, AUTO-Startup assumed");
1955
1956 // If we started within 4 minutes of the next recording,
1957 // we almost certainly started automatically.
1958 autoStart = true;
1959 }
1960 else
1961 {
1962 LOG(VB_GENERAL, LOG_DEBUG,
1963 "NOT close to auto-start time, USER-initiated startup assumed");
1964 }
1965
1966 }
1967 }
1968 }
1969 }
1970
1971 return autoStart;
1972}
1973
1974// from https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=16897
1975// The old way of revoking root with setuid(getuid())
1976// causes system hang in certain cases on raspberry pi
1977
1978static int revokeRoot (void)
1979{
1980 if (getuid () == 0 && geteuid () == 0) // Really running as root
1981 return 0;
1982
1983 if (geteuid () == 0) // Running setuid root
1984 return seteuid (getuid ()) ; // Change effective uid to the uid of the caller
1985 return 0;
1986}
1987
1988
1989Q_DECL_EXPORT int main(int argc, char **argv)
1990{
1991 bool bPromptForBackend = false;
1992 bool bBypassAutoDiscovery = false;
1993
1995 if (!cmdline.Parse(argc, argv))
1996 {
1999 }
2000
2001 if (cmdline.toBool("showhelp"))
2002 {
2004 return GENERIC_EXIT_OK;
2005 }
2006
2007 if (cmdline.toBool("showversion"))
2008 {
2010 return GENERIC_EXIT_OK;
2011 }
2012
2013#if CONFIG_QTWEBENGINE
2014#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2015 QtWebEngineQuick::initialize();
2016#else
2017 QtWebEngine::initialize();
2018#endif
2019#endif
2020
2022 QApplication::setSetuidAllowed(true);
2023 QApplication a(argc, argv);
2024 QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHFRONTEND);
2025
2026#ifdef Q_OS_DARWIN
2027 QString path = QCoreApplication::applicationDirPath();
2028 setenv("PYTHONPATH",
2029 QString("%1/../Resources/lib/%2:/../Resources/lib/%2/site-packages:/../Resources/lib/%2/lib-dynload:%3")
2030 .arg(path)
2031 .arg(QFileInfo(PYTHON_EXE).fileName())
2032 .arg(QProcessEnvironment::systemEnvironment().value("PYTHONPATH"))
2033 .toUtf8().constData(), 1);
2034#endif
2035
2036#ifdef Q_OS_ANDROID
2037 auto config = QSslConfiguration::defaultConfiguration();
2038 config.setCaCertificates(QSslConfiguration::systemCaCertificates());
2039 QSslConfiguration::setDefaultConfiguration(config);
2040#endif
2041
2042 int retval = cmdline.ConfigureLogging();
2043 if (retval != GENERIC_EXIT_OK)
2044 return retval;
2045
2046 bool ResetSettings = false;
2047
2048 if (cmdline.toBool("prompt"))
2049 bPromptForBackend = true;
2050 if (cmdline.toBool("noautodiscovery"))
2051 bBypassAutoDiscovery = true;
2052
2053 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
2054 std::cerr << "Unable to ignore SIGPIPE\n";
2055
2056 if (!cmdline.toString("geometry").isEmpty())
2058
2059 fe_sd_notify("STATUS=Connecting to database.");
2060 MythContext context {MYTH_BINARY_VERSION, true};
2062
2064 if (!context.Init(true, bPromptForBackend, bBypassAutoDiscovery))
2065 {
2066 LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting.");
2067 gCoreContext->SetExiting(true);
2069 }
2070 context.setCleanup(cleanup);
2071
2074
2076
2077 if (!GetMythDB()->HaveSchema())
2078 {
2079 if (!InitializeMythSchema())
2080 return GENERIC_EXIT_DB_ERROR;
2081 }
2082
2083 if (cmdline.toBool("reset"))
2084 ResetSettings = true;
2085
2086 if (!cmdline.toBool("noupnp"))
2087 {
2088 fe_sd_notify("STATUS=Creating UPnP media renderer");
2089 g_pUPnp = new MediaRenderer();
2090 if (!g_pUPnp->isInitialized())
2091 {
2092 delete g_pUPnp;
2093 g_pUPnp = nullptr;
2094 }
2095 }
2096
2097 QString fileprefix = GetConfDir();
2098
2099 QDir dir(fileprefix);
2100 if (!dir.exists())
2101 dir.mkdir(fileprefix);
2102
2103 if (ResetSettings)
2104 {
2106 as.Save();
2107
2109 gCoreContext->GetDB()->ClearSetting("Language");
2110 gCoreContext->GetDB()->ClearSettingOnHost("Language", nullptr);
2111 gCoreContext->GetDB()->ClearSetting("Country");
2112 gCoreContext->GetDB()->ClearSettingOnHost("Country", nullptr);
2113
2114 LOG(VB_GENERAL, LOG_NOTICE, "Appearance settings and language have "
2115 "been reset to defaults. You will need to "
2116 "restart the frontend.");
2117 context.saveSettingsCache();
2118 return GENERIC_EXIT_OK;
2119 }
2120
2121#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2122 int maxImageSize = gCoreContext->GetNumSetting("ImageMaximumSize", -1);
2123 if (maxImageSize >=0)
2124 QImageReader::setAllocationLimit(maxImageSize);
2125#endif
2126 LOG(VB_GENERAL, LOG_DEBUG,
2127 QString("Built against zlib %1, linked against %2.")
2128 .arg(ZLIB_VERSION, zlibVersion()));
2129 QList<QByteArray> formats = QImageReader::supportedImageFormats();
2130 QString format_str = formats.takeFirst();
2131 for (const auto& format : std::as_const(formats))
2132 format_str += ", " + format;
2133 LOG(VB_GENERAL, LOG_DEBUG, QString("Supported image formats: %1").arg(format_str));
2134
2135 QCoreApplication::setSetuidAllowed(true);
2136
2137 if (revokeRoot() != 0)
2138 {
2139 LOG(VB_GENERAL, LOG_ERR, "Failed to revokeRoot(), exiting.");
2140 return GENERIC_EXIT_NOT_OK;
2141 }
2142
2143#if CONFIG_LIBDNS_SD
2144 // this needs to come after gCoreContext has been initialised
2145 // (for hostname) - hence it is not in MediaRenderer
2146 QScopedPointer<BonjourRegister> bonjour(new BonjourRegister());
2147 if (bonjour.data())
2148 {
2149 fe_sd_notify("STATUS=Registering frontend with bonjour");
2150 QByteArray dummy;
2151 int port = gCoreContext->GetNumSetting("UPnP/MythFrontend/ServicePort", 6547);
2152 // frontend upnp server is now ServicePort + 4 (default 6551)
2153 port += 4;
2154 QByteArray name("Mythfrontend on ");
2155 name.append(gCoreContext->GetHostName().toUtf8());
2156 bonjour->Register(port, "_mythfrontend._tcp",
2157 name, dummy);
2158 }
2159#endif
2160
2161 fe_sd_notify("STATUS=Initializing LCD");
2162 LCD::SetupLCD();
2163 if (LCD *lcd = LCD::Get())
2164 lcd->setupLEDs(RemoteGetRecordingMask);
2165
2166 fe_sd_notify("STATUS=Loading translation");
2167 MythTranslation::load("mythfrontend");
2168
2169 fe_sd_notify("STATUS=Loading themes");
2170 QString themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
2171
2172 QString themedir = GetMythUI()->FindThemeDir(themename);
2173 if (themedir.isEmpty())
2174 {
2175 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
2176 .arg(themename));
2177 return GENERIC_EXIT_NO_THEME;
2178 }
2179
2180 themename = gCoreContext->GetSetting("Theme", DEFAULT_UI_THEME);
2181 themedir = GetMythUI()->FindThemeDir(themename);
2182 if (themedir.isEmpty())
2183 {
2184 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find theme '%1'")
2185 .arg(themename));
2186 return GENERIC_EXIT_NO_THEME;
2187 }
2188
2189 auto * mainWindow = GetMythMainWindow();
2190
2191 // Force an update of our hardware decoder/render support once the window is
2192 // ready and we have a render device (and after each window re-initialisation
2193 // when we may have a new render device). This also ensures the support checks
2194 // are done immediately and are not reliant on semi-random settings initialisation.
2195 QObject::connect(mainWindow, &MythMainWindow::SignalWindowReady,
2196 []() { MythVideoProfile::InitStatics(true); } );
2197
2198 mainWindow->Init(false);
2199 mainWindow->setWindowTitle(QCoreApplication::translate("(MythFrontendMain)",
2200 "MythTV Frontend",
2201 "Main window title"));
2202
2203#if CONFIG_AIRPLAY
2204 if (gCoreContext->GetBoolSetting("AirPlayEnabled", true))
2205 {
2206 fe_sd_notify("STATUS=Initializing AirPlay");
2208 if (!gCoreContext->GetBoolSetting("AirPlayAudioOnly", false))
2209 {
2211 }
2212 }
2213#endif
2214
2215 // We must reload the translation after a language change and this
2216 // also means clearing the cached/loaded theme strings, so reload the
2217 // theme which also triggers a translation reload
2219 {
2220 if (!reloadTheme())
2221 return GENERIC_EXIT_NO_THEME;
2222 }
2223
2224 if (!UpgradeTVDatabaseSchema(false, false, true))
2225 {
2226 LOG(VB_GENERAL, LOG_ERR,
2227 "Couldn't upgrade database to new schema, exiting.");
2229 }
2230
2231 WriteDefaults();
2232
2233 // Refresh Global/Main Menu keys after DB update in case there was no DB
2234 // when they were written originally
2235 mainWindow->ReloadKeys();
2236
2237 fe_sd_notify("STATUS=Initializing jump points");
2239 InitKeys();
2240 TV::InitKeys();
2241 SetFuncPtrs();
2242
2244
2246
2247 setHttpProxy();
2248
2249 fe_sd_notify("STATUS=Initializing plugins");
2252
2253 fe_sd_notify("STATUS=Initializing media monitor");
2255 if (mon)
2256 {
2257 mon->StartMonitoring();
2258 mainWindow->installEventFilter(mon);
2259 }
2260
2261 fe_sd_notify("STATUS=Initializing network control");
2262 NetworkControl *networkControl = nullptr;
2263 if (gCoreContext->GetBoolSetting("NetworkControlEnabled", false))
2264 {
2265 int port = gCoreContext->GetNumSetting("NetworkControlPort", 6546);
2266 networkControl = new NetworkControl();
2267 if (!networkControl->listen(port))
2268 {
2269 LOG(VB_GENERAL, LOG_ERR,
2270 QString("NetworkControl failed to bind to port %1.")
2271 .arg(port));
2272 }
2273 }
2274
2275#ifdef Q_OS_DARWIN
2279 gLoaded = true;
2280#endif
2281 if (!RunMenu(themedir, themename) && !resetTheme(themedir, themename))
2282 {
2283 return GENERIC_EXIT_NO_THEME;
2284 }
2285 fe_sd_notify("STATUS=Loading theme updates");
2286 std::unique_ptr<ThemeUpdateChecker> themeUpdateChecker;
2287 if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
2288 themeUpdateChecker = std::make_unique<ThemeUpdateChecker>();
2289
2290 MythSystemEventHandler sysEventHandler {};
2291
2293
2295 PreviewGenerator::kRemote, 50, 60s);
2296
2297 fe_sd_notify("STATUS=Creating housekeeper");
2298 auto *housekeeping = new HouseKeeper();
2299#ifdef __linux__
2300 #ifdef CONFIG_BINDINGS_PYTHON
2301 housekeeping->RegisterTask(new HardwareProfileTask());
2302 #endif
2303#endif
2304 housekeeping->Start();
2305
2306
2307 if (cmdline.toBool("runplugin"))
2308 {
2309 QStringList plugins = g_pmanager->EnumeratePlugins();
2310
2311 if (plugins.contains(cmdline.toString("runplugin")))
2312 g_pmanager->run_plugin(cmdline.toString("runplugin"));
2313 else if (plugins.contains("myth" + cmdline.toString("runplugin")))
2314 g_pmanager->run_plugin("myth" + cmdline.toString("runplugin"));
2315 else
2316 {
2317 LOG(VB_GENERAL, LOG_ERR,
2318 QString("Invalid plugin name supplied on command line: '%1'")
2319 .arg(cmdline.toString("runplugin")));
2320 LOG(VB_GENERAL, LOG_ERR,
2321 QString("Available plugins: %1")
2322 .arg(plugins.join(", ")));
2324 }
2325 }
2326 else if (cmdline.toBool("jumppoint"))
2327 {
2329
2330 if (mmw->DestinationExists(cmdline.toString("jumppoint")))
2331 mmw->JumpTo(cmdline.toString("jumppoint"));
2332 else
2333 {
2334 LOG(VB_GENERAL, LOG_ERR,
2335 QString("Invalid jump point supplied on the command line: %1")
2336 .arg(cmdline.toString("jumppoint")));
2337 LOG(VB_GENERAL, LOG_ERR,
2338 QString("Available jump points: %2")
2339 .arg(mmw->EnumerateDestinations().join(", ")));
2341 }
2342 }
2343
2344 if (WasAutomaticStart())
2345 {
2346 // We appear to have been started automatically
2347 // so enter standby so that the machine can
2348 // shutdown again as soon as possible if necessary.
2349 standbyScreen();
2350 }
2351
2352 // Provide systemd ready notification (for type=notify units)
2353 fe_sd_notify("STATUS=");
2354 fe_sd_notify("READY=1");
2355
2356
2357 int ret = 0;
2358 {
2359 MythHTTPInstance::Addservices({{ FRONTEND_SERVICE, &MythHTTPService::Create<MythFrontendService> }});
2360
2361 // Send all unknown requests into the web app. make bookmarks and direct access work.
2362 auto spa_index = [](auto && PH1) { return MythHTTPRewrite::RewriteToSPA(std::forward<decltype(PH1)>(PH1), "mythfrontend.html"); };
2363 MythHTTPInstance::AddErrorPageHandler({ "=404", spa_index });
2364
2365 auto root = [](auto && PH1) { return MythHTTPRoot::RedirectRoot(std::forward<decltype(PH1)>(PH1), "mythfrontend.html"); };
2366 MythHTTPScopedInstance webserver({{ "/", root}});
2367 ret = QCoreApplication::exec();
2368 }
2369
2370 fe_sd_notify("STOPPING=1\nSTATUS=Exiting");
2371 if (ret==0)
2372 context.saveSettingsCache();
2373
2374 DestroyMythUI();
2376
2377 delete housekeeping;
2378
2380
2381 if (mon)
2382 mon->deleteLater();
2383
2384 delete networkControl;
2385 return ret;
2386}
2387
2389{
2390 LOG(VB_GENERAL, LOG_INFO, "Reloading theme");
2391 gCoreContext->SendMessage("CLEAR_SETTINGS_CACHE");
2393 GetMythMainWindow()->JumpTo("Reload Theme");
2395}
2396
2398{
2399 LOG(VB_GENERAL, LOG_INFO, "Restarting LIRC handler");
2401}
2402
2403/*
2404include Qt MOC output for Q_OBJECT class defined in this file;
2405filenames must match.
2406*/
2407#include "mythfrontend.moc"
2408/* vim: set expandtab tabstop=4 shiftwidth=4: */
std::vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:130
static void Cleanup(void)
Definition: audiooutput.cpp:57
Screen for managing channel priorities in recording scheduling decisions.
@ kChanGroupByChanid
Definition: channelutil.h:217
static ChannelInfoList LoadChannels(uint startIndex, uint count, uint &totalAvailable, bool ignoreHidden=true, OrderBy orderBy=kChanOrderByChanNum, GroupBy groupBy=kChanGroupByChanid, uint sourceID=0, uint channelGroupID=0, bool liveTVOnly=false, const QString &callsign="", const QString &channum="", bool ignoreUntunable=true)
Load channels from database into a list of ChannelInfo objects.
@ kChanOrderByLiveTV
Definition: channelutil.h:210
A screen to create a fully custom recording.
Definition: customedit.h:18
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
Thumbnail screen.
static void RunProgramGuide(uint startChanId, const QString &startChanNum, const QDateTime &startTime, TV *player=nullptr, bool embedVideo=false, bool allowFinder=true, int changrpid=-1)
Definition: guidegrid.cpp:410
Manages registered HouseKeeperTasks and queues tasks for operation.
Definition: housekeeper.h:150
static QStringList SupportedImages()
Return recognised pictures.
static QStringList SupportedVideos()
Return recognised video extensions.
Definition: lcddevice.h:170
static LCD * Get(void)
Definition: lcddevice.cpp:69
static void SetupLCD(void)
Definition: lcddevice.cpp:76
static bool prompt(bool force=false)
Ask the user for the language to use.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
void JumpToMediaHandler(MythMediaDevice *pMedia, bool forcePlayback=false)
Find a relevant jump point for this type of media.
static MediaMonitor * GetMediaMonitor(void)
static QString defaultDVDdevice()
DVDDeviceLocation, user-selected drive, or /dev/dvd.
bool IsActive(void) const
Definition: mediamonitor.h:55
virtual void deleteLater(void)
virtual void StartMonitoring(void)
Start the monitoring thread if needed.
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media.
static bool Create(void)
static void Cleanup(void)
QString GetLastError(void) const
Definition: mythbdinfo.cpp:173
bool GetNameAndSerialNum(QString &Name, QString &SerialNum)
Definition: mythbdinfo.cpp:166
bool IsValid(void) const
Definition: mythbdinfo.cpp:161
static ImageType inspectImage(const QString &path)
Definition: mythcdrom.cpp:188
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
void ApplySettingsOverride(void)
Apply all overrides to the global context.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
void PrintHelp(void) const
Print command line option help.
Startup context for MythTV.
Definition: mythcontext.h:20
Screen for managing and configuring keyboard input bindings.
Definition: mythcontrols.h:49
void emitTVPlaybackStarted(void)
MythDB * GetDB(void)
void emitTVPlaybackStopped(void)
void ClearSettingsCache(const QString &myKey=QString(""))
void ActivateSettingsCache(bool activate=true)
QString GetHostName(void)
static bool BackendIsRunning(void)
a backend process is running on this host
void SaveSetting(const QString &key, int newValue)
void SetExiting(bool exiting=true)
QString GetSetting(const QString &key, const QString &defaultval="")
void OverrideSettingForSession(const QString &key, const QString &value)
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
void SendMessage(const QString &message)
bool IsMasterHost(void)
is this the same host as the master
void SetPluginManager(MythPluginManager *pmanager)
int GetNumSetting(const QString &key, int defaultval=0)
void SetAsFrontend(bool frontend)
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
Basic menu dialog, message and a list of options.
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialisation code for all MythTV GUI applications.
static void AddErrorPageHandler(const HTTPHandler &Handler)
static void Addservices(const HTTPServices &Services)
static HTTPResponse RewriteToSPA(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests to a Single Page web app (SPA)
static HTTPResponse RedirectRoot(const HTTPRequest2 &Request, const QString &File)
A convenience method to seemlessly redirect requests for index.html to a context specific file.
void ClearKeyContext(const QString &Context)
void PauseIdleTimer(bool Pause)
Pause the idle timeout timer.
MythScreenStack * GetMainStack()
void JumpTo(const QString &Destination, bool Pop=true)
MythPainter * GetPainter()
MythScreenStack * GetStack(const QString &Stackname)
bool DestinationExists(const QString &Destination) const
QStringList EnumerateDestinations() const
bool HandleMedia(const QString &Handler, const QString &Mrl, const QString &Plot="", const QString &Title="", const QString &Subtitle="", const QString &Director="", int Season=0, int Episode=0, const QString &Inetref="", std::chrono::minutes LenMins=2h, const QString &Year="1895", const QString &Id="", bool UseBookmarks=false)
void SetEffectsEnabled(bool Enable)
void Init(bool MayReInit=true)
void SignalWindowReady()
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
bool isUsable() const
Is this device "ready", for a plugin to access?
Definition: mythmedia.h:84
void SetDebugMode(bool showBorders, bool showNames)
Definition: mythpainter.h:96
bool ShowBorders(void) const
Definition: mythpainter.h:102
bool ShowTypeNames(void) const
Definition: mythpainter.h:103
void DestroyAllPlugins()
Definition: mythplugin.cpp:223
bool run_plugin(const QString &plugname)
Definition: mythplugin.cpp:162
QStringList EnumeratePlugins(void)
Definition: mythplugin.cpp:235
static bool Create(void)
static void Cleanup(void)
void GetScreenList(QVector< MythScreenType * > &screens)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
virtual MythScreenType * GetTopScreen(void) const
Screen in which all other widgets are contained and rendered.
virtual void Load(void)
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
virtual void Close()
An editor for MythSystemEvent handler commands.
Handles incoming MythSystemEvent messages.
Themed menu class, used for main menus in MythTV frontend.
void setCallback(void(*lcallback)(void *, QString &), void *data)
Set the themed menus callback function and data for that function.
bool foundTheme(void) const
Returns true iff a theme has been found by a previous call to SetMenuTheme().
static void reload()
Reload all active translators based on the current language setting.
static void load(const QString &module_name)
Load a QTranslator for the user's preferred language.
QString RemoveCurrentLocation()
void AddCurrentLocation(const QString &Location)
static void ParseGeometryOverride(const QString &Geometry)
Parse an X11 style command line geometry string.
QString FindThemeDir(const QString &ThemeName, bool Fallback=true)
Returns the full path to the theme denoted by themename.
void SetRedraw(void)
Definition: mythuitype.cpp:313
static void InitStatics(bool Reinit=false)
void SigResultReady(bool passwordValid, ParentalLevel::Level newLevel)
static void * RunPlaybackBox(void *player, bool showTV)
void Load(void) override
static void CreatePreviewGeneratorQueue(PreviewGenerator::Mode mode, uint maxAttempts, std::chrono::seconds minBlockSeconds)
Create the singleton queue of preview generators.
static void TeardownPreviewGeneratorQueue()
Destroy the singleton queue of preview generators.
static void * RunProgramList(void *player, ProgListType pltype, const QString &extraArg)
Definition: proglist.cpp:37
Holds information on recordings and videos.
Definition: programinfo.h:70
static void * RunScheduleEditor(ProgramInfo *proginfo, void *player=nullptr)
Callback.
bool listen(QList< QHostAddress > addrs, quint16 port, bool requireall=true, PoolServerType type=kTCPServer)
Definition: serverpool.cpp:395
void RunProlog(const QString &settingsPage)
void RunEpilog(void)
static void SetHandler(int signum, SigHandlerFunc handler)
bool Create(void) override
virtual void Save(void)
virtual void Load(void)
Reports on various status items.
Definition: statusbox.h:38
static void SetFuncPtr(const char *Name, void *Pointer)
Import pointers to functions used to embed the TV window into other containers e.g.
Definition: tv_play.cpp:477
static bool StartTV(ProgramInfo *TVRec, uint Flags, const ChannelInfoList &Selection=ChannelInfoList())
Start playback of media.
Definition: tv_play.cpp:287
static int ConfiguredTunerCards()
If any cards are configured, return the number.
Definition: tv_play.cpp:118
static void InitKeys()
Definition: tv_play.cpp:494
View and select installed themes.
Definition: themechooser.h:28
bool isInitialized()
Definition: upnp.h:118
@ DLG_DEFAULT
Definition: videodlg.h:38
@ DLG_MANAGER
Definition: videodlg.h:39
@ DLG_GALLERY
Definition: videodlg.h:38
@ DLG_BROWSER
Definition: videodlg.h:38
static VideoListDeathDelayPtr & GetSavedVideoList()
Definition: videodlg.cpp:878
QPointer< class VideoListDeathDelay > VideoListDeathDelayPtr
Definition: videodlg.h:48
@ BRS_FOLDER
Definition: videodlg.h:42
static constexpr std::chrono::milliseconds kDelayTimeMS
Definition: videodlg.h:239
Screen for viewing and managing upcoming and conflicted recordings.
Definition: viewscheduled.h:30
static void * RunViewScheduled(void *player, bool showTv)
This dialog is used when playing something from the "Watch Videos" page. Playing from the "Watch Reco...
BookmarkDialog(ProgramInfo *pginfo, MythScreenStack *parent, bool bookmarkPresent, bool lastPlayPresent)
void OnPasswordResultReady(bool passwordValid, ParentalLevel::Level newLevel)
#define seteuid(x)
Definition: compat.h:176
#define geteuid()
Definition: compat.h:174
#define SIGPIPE
Definition: compat.h:129
unsigned int uint
Definition: compat.h:68
#define getuid()
Definition: compat.h:173
#define SIGUSR1
Definition: compat.h:127
#define setenv(x, y, z)
Definition: compat.h:76
#define SIGUSR2
Definition: compat.h:128
bool InitializeMythSchema(void)
command to get the the initial database layout from an empty database:
Definition: dbcheck.cpp:1272
bool UpgradeTVDatabaseSchema(const bool upgradeAllowed, const bool upgradeIfNoUI, const bool informSystemd)
Called from outside dbcheck.cpp to update the schema.
Definition: dbcheck.cpp:362
@ GENERIC_EXIT_NO_MYTHCONTEXT
No MythContext available.
Definition: exitcodes.h:16
@ GENERIC_EXIT_DB_OUTOFDATE
Database needs upgrade.
Definition: exitcodes.h:19
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ GENERIC_EXIT_NO_THEME
No Theme available.
Definition: exitcodes.h:17
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
@ GENERIC_EXIT_DB_ERROR
Database error.
Definition: exitcodes.h:20
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:14
Implements Gallery Thumbnail screen.
const QString JUMP_VIDEO_TREE
Definition: globals.cpp:38
const QString JUMP_VIDEO_GALLERY
Definition: globals.cpp:39
const QString JUMP_VIDEO_MANAGER
Definition: globals.cpp:36
const QString JUMP_VIDEO_DEFAULT
Definition: globals.cpp:40
const QString JUMP_VIDEO_BROWSER
Definition: globals.cpp:37
const QString JUMP_GALLERY_DEFAULT
Definition: globals.cpp:42
static guint32 * tmp
Definition: goom_core.cpp:26
@ quit
Definition: lirc_client.h:30
static void REG_MEDIA_HANDLER(const QString &destination, const QString &description, MediaCallback callback, int mediaType, const QString &extensions)
Definition: mediamonitor.h:141
static constexpr const char * MYTH_APPNAME_MYTHFRONTEND
Definition: mythappname.h:6
Main header for mythcontrols.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDB * GetMythDB(void)
Definition: mythdb.cpp:51
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
QString GetAppBinDir(void)
Definition: mythdirs.cpp:260
static QString themedir
Definition: mythdirs.cpp:23
QString GetConfDir(void)
Definition: mythdirs.cpp:263
static void startKeysSetup()
static void startPlaybackWithGroup(const QString &recGroup="")
static void WriteDefaults()
static bool RunMenu(const QString &themedir, const QString &themename)
static void startManaged(void)
static void startChannelRecPriorities(void)
static void startTVNormal(void)
static void startSearchTime(void)
static void startSearchStored(void)
static void startGuide(void)
static bool isLiveTVAvailable(void)
static void standbyScreen(void)
static void startManageRecordingRules(void)
static void startSearchNew(void)
static void resetAllKeys(void)
Reset this host's key bindings and jump points to default values.
static void startPlayback(void)
static void RunGallery()
static void TVMenuCallback(void *, QString &selection)
static SettingsHelper * g_settingsHelper
void handleSIGUSR1(void)
static MythPluginManager * g_pmanager
static void jumpScreenVideoDefault()
static void setDebugShowNames(void)
static void startSearchCategory(void)
static MediaRenderer * g_pUPnp
static void InitJumpPoints(void)
static void ReloadKeys(void)
static int internal_play_media(const QString &mrl, const QString &plot, const QString &title, const QString &subtitle, const QString &director, int season, int episode, const QString &inetref, std::chrono::minutes lenMins, const QString &year, const QString &id, const bool useBookmark)
static void startPreviousOld(void)
static void SetFuncPtrs(void)
static void jumpScreenVideoBrowser()
static int reloadTheme(void)
void handleSIGUSR2(void)
static void playDisc()
static void startCustomEdit(void)
static void jumpScreenVideoGallery()
static void startSearchKeyword(void)
static void handleDVDMedia(MythMediaDevice *dvd, bool)
static void showStatus(void)
static void startSearchPeople(void)
static void startSearchPower(void)
static MythThemedMenu * g_menu
static void startFinder(void)
static void gotoMainMenu(void)
static void handleGalleryMedia(MythMediaDevice *dev, bool forcePlayback)
static void startPrevious(void)
static void startSearchTitle(void)
Q_DECL_EXPORT int main(int argc, char **argv)
static void clearAllKeys(void)
Deletes all key bindings and jump points for this host.
static void startSearchMovie(void)
static bool WasAutomaticStart(void)
static void ReloadJumpPoints(void)
static void startSearchChannel(void)
static void jumpScreenVideoManager()
static void startAppearWiz(void)
static int internal_media_init()
static void fe_sd_notify(const char *)
static void reloadTheme_void(void)
static bool resetTheme(QString themedir, const QString &badtheme)
static int revokeRoot(void)
static void startCustomPriority(void)
static void InitKeys(void)
static void CleanupMyOldInUsePrograms(void)
static void jumpScreenVideoTree()
static void startManualSchedule(void)
static void handleExit(bool prompt)
static void RunVideoScreen(VideoDialog::DialogType type, bool fromJump=false)
static void setDebugShowBorders(void)
static const QString sLocation
#define FRONTEND_SERVICE
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
static void REG_JUMPLOC(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void), const QString &LocalAction)
static void REG_JUMPEX(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void), bool ExitToMain)
static void REG_MEDIAPLAYER(const QString &Name, const QString &Desc, MediaPlayCallback Func)
static void REG_JUMP(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void))
static void REG_KEY(const QString &Context, const QString &Action, const QString &Description, const QString &Key)
@ MEDIATYPE_DVD
Definition: mythmedia.h:29
@ MEDIATYPE_MIXED
Definition: mythmedia.h:27
@ MEDIATYPE_AUDIO
Definition: mythmedia.h:28
@ MEDIATYPE_MGALLERY
Definition: mythmedia.h:33
@ MEDIATYPE_MVIDEO
Definition: mythmedia.h:32
@ MEDIATYPE_DATA
Definition: mythmedia.h:26
@ MEDIASTAT_USEABLE
Definition: mythmedia.h:19
@ MEDIASTAT_MOUNTED
Definition: mythmedia.h:21
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
@ kMSPropagateLogs
add arguments for MythTV log propagation
Definition: mythsystem.h:52
@ kMSDisableUDPListener
disable MythMessage UDP listener for the duration of application.
Definition: mythsystem.h:50
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
void DestroyMythUI()
MythUIHelper * GetMythUI()
static constexpr const char * FALLBACK_UI_THEME
static constexpr const char * DEFAULT_UI_THEME
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:212
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
MythCommFlagCommandLineParser cmdline
string hostname
Definition: caa.py:17
void RunProgramFinder(TV *player, bool embedVideo, bool allowEPG)
Definition: progfind.cpp:32
@ plKeywordSearch
Definition: proglist.h:21
@ plTime
Definition: proglist.h:29
@ plChannel
Definition: proglist.h:28
@ plTitleSearch
Definition: proglist.h:20
@ plPowerSearch
Definition: proglist.h:23
@ plMovies
Definition: proglist.h:26
@ plCategory
Definition: proglist.h:27
@ plPeopleSearch
Definition: proglist.h:22
@ plNewListings
Definition: proglist.h:25
@ plStoredSearch
Definition: proglist.h:31
bool LoadFromScheduler(AutoDeleteDeque< TYPE * > &destination, bool &hasConflicts, const QString &altTable="", int recordid=-1)
Definition: programinfo.h:939
@ kStartTVIgnoreLastPlayPos
Definition: tv_play.h:118
@ kStartTVNoFlags
Definition: tv_play.h:113
@ kStartTVIgnoreBookmark
Definition: tv_play.h:116
int RemoteGetFreeRecorderCount(void)
int RemoteGetRecordingMask(void)
const std::array< const std::string, 8 > formats
Definition: vbilut.cpp:189