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