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