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