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