00001 #include <qapplication.h>
00002 #include <qsqldatabase.h>
00003 #include <qfile.h>
00004 #include <qfileinfo.h>
00005 #include <qmap.h>
00006 #include <unistd.h>
00007 #include <stdlib.h>
00008 #include <qdir.h>
00009 #include <qtextcodec.h>
00010 #include <qwidget.h>
00011 #include <fcntl.h>
00012 #include <signal.h>
00013 #include <cerrno>
00014 #include <pthread.h>
00015
00016 #include <iostream>
00017 using namespace std;
00018
00019 #include "mythconfig.h"
00020 #include "tv.h"
00021 #include "proglist.h"
00022 #include "progfind.h"
00023 #include "manualbox.h"
00024 #include "manualschedule.h"
00025 #include "playbackbox.h"
00026 #include "previouslist.h"
00027 #include "customedit.h"
00028 #include "viewscheduled.h"
00029 #include "programrecpriority.h"
00030 #include "channelrecpriority.h"
00031 #include "custompriority.h"
00032 #include "globalsettings.h"
00033 #include "profilegroup.h"
00034 #include "playgroup.h"
00035 #include "networkcontrol.h"
00036 #include "DVDRingBuffer.h"
00037
00038 #include "libmyth/compat.h"
00039 #include "exitcodes.h"
00040 #include "programinfo.h"
00041 #include "mythcontext.h"
00042 #include "mythdbcon.h"
00043 #include "dialogbox.h"
00044 #include "guidegrid.h"
00045 #include "mythplugin.h"
00046 #include "remoteutil.h"
00047 #include "xbox.h"
00048 #include "dbcheck.h"
00049 #include "mythmediamonitor.h"
00050 #include "statusbox.h"
00051 #include "lcddevice.h"
00052 #include "langsettings.h"
00053 #include "dbutil.h"
00054
00055 #include "myththemedmenu.h"
00056 #include "myththemebase.h"
00057 #include "mediarenderer.h"
00058 #include "mythscreenstack.h"
00059 #include "mythmainwindow.h"
00060 #include "mythappearance.h"
00061 #include "audiopulseutil.h"
00062
00063 #define NO_EXIT 0
00064 #define QUIT 1
00065 #define HALT 2
00066 #define REBOOT 3
00067
00068 static MythThemedMenu *menu;
00069 static MythThemeBase *themeBase;
00070
00071 XBox *xbox = NULL;
00072 QString logfile = "";
00073
00074 MediaRenderer *g_pUPnp = NULL;
00075
00076 void startAppearWiz(void)
00077 {
00078 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00079
00080 MythAppearance *mythappearance = new MythAppearance(mainStack, "mythappearance");
00081
00082 if (mythappearance->Create())
00083 mainStack->AddScreen(mythappearance);
00084 }
00085
00086
00087 void startGuide(void)
00088 {
00089 uint chanid = 0;
00090 QString channum = gContext->GetSetting("DefaultTVChannel");
00091 channum = (channum.isEmpty()) ? "3" : channum;
00092 GuideGrid::Run(chanid, channum);
00093 }
00094
00095 void startFinder(void)
00096 {
00097 RunProgramFind();
00098 }
00099
00100 void startSearchTitle(void)
00101 {
00102 ProgLister searchTitle(plTitleSearch, "", "",
00103 gContext->GetMainWindow(), "proglist");
00104
00105 qApp->unlock();
00106 searchTitle.exec();
00107 qApp->lock();
00108 }
00109
00110 void startSearchKeyword(void)
00111 {
00112 ProgLister searchKeyword(plKeywordSearch, "", "",
00113 gContext->GetMainWindow(), "proglist");
00114
00115 qApp->unlock();
00116 searchKeyword.exec();
00117 qApp->lock();
00118 }
00119
00120 void startSearchPeople(void)
00121 {
00122 ProgLister searchPeople(plPeopleSearch, "", "",
00123 gContext->GetMainWindow(), "proglist");
00124
00125 qApp->unlock();
00126 searchPeople.exec();
00127 qApp->lock();
00128 }
00129
00130 void startSearchPower(void)
00131 {
00132 ProgLister searchPower(plPowerSearch, "", "",
00133 gContext->GetMainWindow(), "proglist");
00134
00135 qApp->unlock();
00136 searchPower.exec();
00137 qApp->lock();
00138 }
00139
00140 void startSearchStored(void)
00141 {
00142 ProgLister searchStored(plStoredSearch, "", "",
00143 gContext->GetMainWindow(), "proglist");
00144
00145 qApp->unlock();
00146 searchStored.exec();
00147 qApp->lock();
00148 }
00149
00150 void startSearchChannel(void)
00151 {
00152 ProgLister searchChannel(plChannel, "", "",
00153 gContext->GetMainWindow(), "proglist");
00154
00155 qApp->unlock();
00156 searchChannel.exec();
00157 qApp->lock();
00158 }
00159
00160 void startSearchCategory(void)
00161 {
00162 ProgLister searchCategory(plCategory, "", "",
00163 gContext->GetMainWindow(), "proglist");
00164
00165 qApp->unlock();
00166 searchCategory.exec();
00167 qApp->lock();
00168 }
00169
00170 void startSearchMovie(void)
00171 {
00172 ProgLister searchMovie(plMovies, "", "",
00173 gContext->GetMainWindow(), "proglist");
00174
00175 qApp->unlock();
00176 searchMovie.exec();
00177 qApp->lock();
00178 }
00179
00180 void startSearchNew(void)
00181 {
00182 ProgLister searchNew(plNewListings, "", "",
00183 gContext->GetMainWindow(), "proglist");
00184
00185 qApp->unlock();
00186 searchNew.exec();
00187 qApp->lock();
00188 }
00189
00190 void startSearchTime(void)
00191 {
00192 ProgLister searchTime(plTime, "", "",
00193 gContext->GetMainWindow(), "proglist");
00194
00195 qApp->unlock();
00196 searchTime.exec();
00197 qApp->lock();
00198 }
00199
00200 void startManaged(void)
00201 {
00202 ViewScheduled vsb(gContext->GetMainWindow(), "view scheduled");
00203
00204 qApp->unlock();
00205 vsb.exec();
00206 qApp->lock();
00207 }
00208
00209 void startProgramRecPriorities(void)
00210 {
00211 ProgramRecPriority rsb(gContext->GetMainWindow(), "recpri scheduled");
00212
00213 qApp->unlock();
00214 rsb.exec();
00215 qApp->lock();
00216 }
00217
00218 void startChannelRecPriorities(void)
00219 {
00220 ChannelRecPriority rch(gContext->GetMainWindow(), "recpri channels");
00221
00222 qApp->unlock();
00223 rch.exec();
00224 qApp->lock();
00225 }
00226
00227 void startCustomPriority(void)
00228 {
00229 CustomPriority custom(gContext->GetMainWindow(), "custom priority");
00230
00231 qApp->unlock();
00232 custom.exec();
00233 qApp->lock();
00234 }
00235
00236 void startPlayback(void)
00237 {
00238 PlaybackBox pbb(PlaybackBox::Play, gContext->GetMainWindow(),
00239 "tvplayselect");
00240
00241 qApp->unlock();
00242 pbb.exec();
00243 qApp->lock();
00244 }
00245
00246 void startDelete(void)
00247 {
00248 PlaybackBox delbox(PlaybackBox::Delete, gContext->GetMainWindow(),
00249 "tvplayselect");
00250
00251 qApp->unlock();
00252 delbox.exec();
00253 qApp->lock();
00254 }
00255
00256 void startPrevious(void)
00257 {
00258 PreviousList previous(gContext->GetMainWindow(), "previous list");
00259
00260 qApp->unlock();
00261 previous.exec();
00262 qApp->lock();
00263 }
00264
00265 void startCustomEdit(void)
00266 {
00267 CustomEdit custom(gContext->GetMainWindow(), "custom record");
00268
00269 qApp->unlock();
00270 custom.exec();
00271 qApp->lock();
00272 }
00273
00274 void startManual(void)
00275 {
00276 ManualBox manbox(gContext->GetMainWindow(), "manual box");
00277
00278 qApp->unlock();
00279 manbox.exec();
00280 qApp->lock();
00281 }
00282
00283 void startManualSchedule(void)
00284 {
00285 ManualSchedule mansched(gContext->GetMainWindow(), "manual schedule");
00286
00287 qApp->unlock();
00288 mansched.exec();
00289 qApp->lock();
00290 }
00291
00292 void startTVInGuide(void)
00293 {
00294 TV::StartTV(NULL, true);
00295 }
00296
00297 void startTVNormal(void)
00298 {
00299 TV::StartTV(NULL, false);
00300 }
00301
00302 void showStatus(void)
00303 {
00304 StatusBox statusbox(gContext->GetMainWindow(), "status box");
00305 if (statusbox.IsErrored())
00306 {
00307 MythPopupBox::showOkPopup(
00308 gContext->GetMainWindow(), QObject::tr("Theme Error"),
00309 QString(QObject::tr(
00310 "Your theme does not contain elements required "
00311 "to display the status screen.")));
00312 }
00313 else
00314 {
00315 qApp->unlock();
00316 statusbox.exec();
00317 qApp->lock();
00318 }
00319 }
00320
00321 void TVMenuCallback(void *data, QString &selection)
00322 {
00323 (void)data;
00324 QString sel = selection.lower();
00325
00326 if (sel.left(9) == "settings ")
00327 {
00328 gContext->addCurrentLocation("Setup");
00329 gContext->ActivateSettingsCache(false);
00330 }
00331
00332 if (sel == "tv_watch_live")
00333 startTVNormal();
00334 else if (sel == "tv_watch_live_epg")
00335 startTVInGuide();
00336 else if (sel == "tv_watch_recording")
00337 startPlayback();
00338 else if (sel == "tv_schedule")
00339 startGuide();
00340 else if (sel == "tv_delete")
00341 startDelete();
00342 else if (sel == "tv_manual")
00343 startManual();
00344 else if (sel == "tv_manualschedule")
00345 startManualSchedule();
00346 else if (sel == "tv_custom_record")
00347 startCustomEdit();
00348 else if (sel == "tv_fix_conflicts")
00349 startManaged();
00350 else if (sel == "tv_set_recpriorities")
00351 startProgramRecPriorities();
00352 else if (sel == "tv_progfind")
00353 startFinder();
00354 else if (sel == "tv_search_title")
00355 startSearchTitle();
00356 else if (sel == "tv_search_keyword")
00357 startSearchKeyword();
00358 else if (sel == "tv_search_people")
00359 startSearchPeople();
00360 else if (sel == "tv_search_power")
00361 startSearchPower();
00362 else if (sel == "tv_search_stored")
00363 startSearchStored();
00364 else if (sel == "tv_search_channel")
00365 startSearchChannel();
00366 else if (sel == "tv_search_category")
00367 startSearchCategory();
00368 else if (sel == "tv_search_movie")
00369 startSearchMovie();
00370 else if (sel == "tv_search_new")
00371 startSearchNew();
00372 else if (sel == "tv_search_time")
00373 startSearchTime();
00374 else if (sel == "tv_previous")
00375 startPrevious();
00376 else if (sel == "settings appearance")
00377 {
00378 AppearanceSettings *settings = new AppearanceSettings();
00379 DialogCode res = settings->exec();
00380 delete settings;
00381
00382 if (kDialogCodeRejected != res)
00383 {
00384 qApp->processEvents();
00385 GetMythMainWindow()->JumpTo("Reload Theme");
00386 }
00387 }
00388
00389 else if (sel == "screensetupwizard")
00390 {
00391 startAppearWiz();
00392 }
00393
00394 else if (sel == "settings recording")
00395 {
00396 ProfileGroupEditor editor;
00397 editor.exec();
00398 }
00399 else if (sel == "settings playgroup")
00400 {
00401 PlayGroupEditor editor;
00402 editor.exec();
00403 }
00404 else if (sel == "settings general")
00405 {
00406 GeneralSettings settings;
00407 settings.exec();
00408 }
00409 else if (sel == "settings maingeneral")
00410 {
00411 MainGeneralSettings mainsettings;
00412 mainsettings.exec();
00413 menu->ReloadExitKey();
00414 QStringList strlist = QString("REFRESH_BACKEND");
00415 gContext->SendReceiveStringList(strlist);
00416 }
00417 else if (sel == "settings playback")
00418 {
00419 PlaybackSettings settings;
00420 settings.exec();
00421 }
00422 else if (sel == "settings osd")
00423 {
00424 OSDSettings settings;
00425 settings.exec();
00426 }
00427 else if (sel == "settings epg")
00428 {
00429 EPGSettings settings;
00430 settings.exec();
00431 }
00432 else if (sel == "settings generalrecpriorities")
00433 {
00434 GeneralRecPrioritiesSettings settings;
00435 settings.exec();
00436 }
00437 else if (sel == "settings channelrecpriorities")
00438 {
00439 startChannelRecPriorities();
00440 }
00441 else if (sel == "settings custompriority")
00442 {
00443 startCustomPriority();
00444 }
00445 else if (xbox && sel == "settings xboxsettings")
00446 {
00447 XboxSettings settings;
00448 settings.exec();
00449
00450 xbox->GetSettings();
00451 }
00452 else if (sel == "tv_status")
00453 showStatus();
00454
00455 if (sel.left(9) == "settings ")
00456 {
00457 gContext->removeCurrentLocation();
00458
00459 gContext->ActivateSettingsCache(true);
00460 RemoteSendMessage("CLEAR_SETTINGS_CACHE");
00461
00462 if (sel == "settings general" ||
00463 sel == "settings generalrecpriorities")
00464 ScheduledRecording::signalChange(0);
00465 }
00466 }
00467
00468 int handleExit(void)
00469 {
00470 if (gContext->GetNumSetting("NoPromptOnExit", 1) == 0)
00471 return QUIT;
00472
00473
00474 bool frontendOnly = gContext->IsFrontendOnly();
00475
00476
00477 int exitMenuStyle = gContext->GetNumSetting("OverrideExitMenu", 0);
00478
00479 QString title = QObject::tr("Do you really want to exit MythTV?");
00480
00481 DialogBox *dlg = new DialogBox(gContext->GetMainWindow(), title);
00482
00483 dlg->AddButton(QObject::tr("No"));
00484 DialogCode result = kDialogCodeRejected;
00485
00486 int ret = NO_EXIT;
00487 switch (exitMenuStyle)
00488 {
00489 case 0:
00490 dlg->AddButton(QObject::tr("Yes, Exit now"));
00491 if (frontendOnly)
00492 dlg->AddButton(QObject::tr("Yes, Exit and Shutdown"));
00493 result = dlg->exec();
00494 switch (result)
00495 {
00496 case kDialogCodeButton0: ret = NO_EXIT; break;
00497 case kDialogCodeButton1: ret = QUIT; break;
00498 case kDialogCodeButton2: ret = HALT; break;
00499 default: ret = NO_EXIT; break;
00500 }
00501 break;
00502 case 1:
00503 dlg->AddButton(QObject::tr("Yes, Exit now"));
00504 result = dlg->exec();
00505 switch (result)
00506 {
00507 case kDialogCodeButton0: ret = NO_EXIT; break;
00508 case kDialogCodeButton1: ret = QUIT; break;
00509 default: ret = NO_EXIT; break;
00510 }
00511 break;
00512 case 2:
00513 dlg->AddButton(QObject::tr("Yes, Exit now"));
00514 dlg->AddButton(QObject::tr("Yes, Exit and Shutdown"));
00515 result = dlg->exec();
00516 switch (result)
00517 {
00518 case kDialogCodeButton0: ret = NO_EXIT; break;
00519 case kDialogCodeButton1: ret = QUIT; break;
00520 case kDialogCodeButton2: ret = HALT; break;
00521 default: ret = NO_EXIT; break;
00522 }
00523 break;
00524 case 3:
00525 dlg->AddButton(QObject::tr("Yes, Exit now"));
00526 dlg->AddButton(QObject::tr("Yes, Exit and Reboot"));
00527 dlg->AddButton(QObject::tr("Yes, Exit and Shutdown"));
00528 result = dlg->exec();
00529 switch (result)
00530 {
00531 case kDialogCodeButton0: ret = NO_EXIT; break;
00532 case kDialogCodeButton1: ret = QUIT; break;
00533 case kDialogCodeButton2: ret = REBOOT; break;
00534 case kDialogCodeButton3: ret = HALT; break;
00535 default: ret = NO_EXIT; break;
00536 }
00537 break;
00538 case 4:
00539 dlg->AddButton(QObject::tr("Yes, Exit and Shutdown"));
00540 result = dlg->exec();
00541 switch (result)
00542 {
00543 case kDialogCodeButton0: ret = NO_EXIT; break;
00544 case kDialogCodeButton1: ret = HALT; break;
00545 default: ret = NO_EXIT; break;
00546 }
00547 break;
00548 case 5:
00549 dlg->AddButton(QObject::tr("Yes, Exit and Reboot"));
00550 result = dlg->exec();
00551 switch (result)
00552 {
00553 case kDialogCodeButton0: ret = NO_EXIT; break;
00554 case kDialogCodeButton1: ret = REBOOT; break;
00555 default: ret = NO_EXIT; break;
00556 }
00557 break;
00558 case 6:
00559 dlg->AddButton(QObject::tr("Yes, Exit and Reboot"));
00560 dlg->AddButton(QObject::tr("Yes, Exit and Shutdown"));
00561 result = dlg->exec();
00562 switch (result)
00563 {
00564 case kDialogCodeButton0: ret = NO_EXIT; break;
00565 case kDialogCodeButton1: ret = REBOOT; break;
00566 case kDialogCodeButton2: ret = HALT; break;
00567 default: ret = NO_EXIT; break;
00568 }
00569 break;
00570 }
00571
00572 dlg->deleteLater();
00573 dlg = NULL;
00574
00575 return ret;
00576 }
00577
00578 void haltnow()
00579 {
00580 QString halt_cmd = gContext->GetSetting("HaltCommand",
00581 "sudo /sbin/halt -p");
00582 if (!halt_cmd.isEmpty())
00583 system(halt_cmd.ascii());
00584 }
00585
00586 void rebootnow()
00587 {
00588 QString reboot_cmd = gContext->GetSetting("RebootCommand",
00589 "sudo /sbin/reboot");
00590 if (!reboot_cmd.isEmpty())
00591 system(reboot_cmd.ascii());
00592 }
00593
00594 bool RunMenu(QString themedir)
00595 {
00596 menu = new MythThemedMenu(themedir.ascii(), "mainmenu.xml",
00597 GetMythMainWindow()->GetMainStack(), "mainmenu");
00598 menu->setCallback(TVMenuCallback, gContext);
00599
00600 if (menu->foundTheme())
00601 {
00602 GetMythMainWindow()->GetMainStack()->AddScreen(menu);
00603 return true;
00604 }
00605
00606 cerr << "Couldn't find theme " << themedir << endl;
00607 return false;
00608 }
00609
00610
00611
00612 void WriteDefaults()
00613 {
00614 PlaybackSettings ps;
00615 ps.load();
00616 ps.save();
00617 OSDSettings os;
00618 os.load();
00619 os.save();
00620 GeneralSettings gs;
00621 gs.load();
00622 gs.save();
00623 EPGSettings es;
00624 es.load();
00625 es.save();
00626 AppearanceSettings as;
00627 as.load();
00628 as.save();
00629 MainGeneralSettings mgs;
00630 mgs.load();
00631 mgs.save();
00632 GeneralRecPrioritiesSettings grs;
00633 grs.load();
00634 grs.save();
00635 }
00636
00637 QString RandTheme(QString &themename)
00638 {
00639 QDir themes(gContext->GetThemesParentDir());
00640 themes.setFilter(QDir::Dirs);
00641
00642 const QFileInfoList *fil = themes.entryInfoList(QDir::Dirs);
00643
00644 QFileInfoListIterator it( *fil);
00645 QFileInfo *theme;
00646 QStringList themelist;
00647
00648 srand(time(NULL));
00649
00650 for ( ; it.current() !=0; ++it)
00651 {
00652 theme = it.current();
00653 if (theme->fileName() == "." || theme->fileName() =="..")
00654 continue;
00655
00656 QFileInfo xml(theme->absFilePath() + "/theme.xml");
00657
00658 if (!xml.exists())
00659 continue;
00660
00661
00662 if (theme->fileName() != themename)
00663 themelist.append(theme->fileName());
00664 }
00665
00666 if (themelist.size())
00667 themename = themelist[rand() % themelist.size()];
00668
00669 gContext->SaveSetting("Theme", themename);
00670
00671 return themename;
00672 }
00673
00674 int internal_play_media(const QString &mrl, const QString &plot,
00675 const QString &title, const QString &director,
00676 int lenMins, const QString &year)
00677 {
00678 int res = -1;
00679
00680 QFile checkFile(mrl);
00681 if (!checkFile.exists() && !mrl.startsWith("dvd:"))
00682 {
00683 QString errorText = QObject::tr("Failed to open \n '%1' in %2 \n"
00684 "Check if the video exists")
00685 .arg(mrl.section("/", -1))
00686 .arg(mrl.section("/", 0, -2));
00687 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00688 "Open Failed",
00689 errorText);
00690 return res;
00691 }
00692
00693 ProgramInfo *pginfo = new ProgramInfo();
00694 pginfo->recstartts = QDateTime::currentDateTime()
00695 .addSecs((0 - (lenMins + 1)) * 60 );
00696 pginfo->recendts = QDateTime::currentDateTime().addSecs(-60);
00697 pginfo->startts.setDate(QDate::fromString(QString("%1-01-01").arg(year),
00698 Qt::ISODate));
00699 pginfo->lenMins = lenMins;
00700 pginfo->isVideo = true;
00701 pginfo->pathname = mrl;
00702
00703 QDir d(mrl + "/VIDEO_TS");
00704 if (mrl.findRev(".iso", -1, false) == (int)mrl.length() - 4 ||
00705 mrl.findRev(".img", -1, false) == (int)mrl.length() - 4 ||
00706 d.exists())
00707 {
00708 pginfo->pathname = QString("dvd:%1").arg(mrl);
00709 }
00710
00711 pginfo->description = plot;
00712
00713 if (director.length())
00714 pginfo->subtitle = QString( "%1: %2" ).arg(QObject::tr("Directed By")).arg(director);
00715
00716 pginfo->title = title;
00717
00718 if (pginfo->pathname.startsWith("dvd:"))
00719 {
00720 bool allowdvdbookmark = gContext->GetNumSetting("EnableDVDBookmark", 0);
00721 pginfo->setIgnoreBookmark(!allowdvdbookmark);
00722 if (allowdvdbookmark &&
00723 gContext->GetNumSetting("DVDBookmarkPrompt", 0))
00724 {
00725 RingBuffer *tmprbuf = new RingBuffer(pginfo->pathname, false);
00726 QString name;
00727 QString serialid;
00728 if (tmprbuf->isDVD() &&
00729 tmprbuf->DVD()->GetNameAndSerialNum(name, serialid))
00730 {
00731 QStringList fields = pginfo->GetDVDBookmark(serialid, false);
00732 if (!fields.empty())
00733 {
00734 QStringList::Iterator it = fields.begin();
00735 long long pos = (long long)(atoi((*++it).ascii()) & 0xffffffffLL);
00736 if (pos > 0)
00737 {
00738 QString msg = QObject::tr("DVD contains a bookmark");
00739 QString btn0msg = QObject::tr("Play from bookmark");
00740 QString btn1msg = QObject::tr("Play from beginning");
00741
00742 DialogCode ret = MythPopupBox::Show2ButtonPopup(
00743 gContext->GetMainWindow(),
00744 "", msg,
00745 btn0msg,
00746 btn1msg,
00747 kDialogCodeButton0);
00748 if (kDialogCodeButton1 == ret)
00749 pginfo->setIgnoreBookmark(true);
00750 else if (kDialogCodeRejected == ret)
00751 {
00752 delete tmprbuf;
00753 delete pginfo;
00754 return res;
00755 }
00756 }
00757 }
00758 }
00759 delete tmprbuf;
00760 }
00761 }
00762
00763 TV::StartTV(pginfo);
00764
00765 res = 0;
00766
00767 sleep(1);
00768 delete pginfo;
00769
00770 return res;
00771 }
00772
00773 void gotoMainMenu(void)
00774 {
00775
00776
00777 QKeyEvent *event =
00778 new QKeyEvent(QEvent::KeyPress, Qt::Key_L, 0, Qt::ControlButton);
00779 QApplication::postEvent((QObject*)(gContext->GetMainWindow()), event);
00780 }
00781
00782 void reloadTheme(void)
00783 {
00784 LanguageSettings::reload();
00785
00786 gContext->LoadQtConfig();
00787 gContext->GetMainWindow()->Init();
00788 gContext->UpdateImageCache();
00789
00790 themeBase->Reload();
00791 menu->ReloadTheme();
00792
00793 if (!menu->foundTheme())
00794 exit(FRONTEND_BUGGY_EXIT_NO_THEME);
00795
00796 LCD::SetupLCD();
00797 if (LCD *lcd = LCD::Get())
00798 {
00799 lcd->setupLEDs(RemoteGetRecordingMask);
00800 lcd->resetServer();
00801 }
00802 }
00803
00804 void InitJumpPoints(void)
00805 {
00806 REG_JUMP("Reload Theme", "", "", reloadTheme);
00807 REG_JUMP("Main Menu", "", "", gotoMainMenu);
00808 REG_JUMPLOC("Program Guide", "", "", startGuide, "GUIDE");
00809 REG_JUMPLOC("Program Finder", "", "", startFinder, "FINDER");
00810
00811 REG_JUMPLOC("Manage Recordings / Fix Conflicts", "", "",
00812 startManaged, "VIEWSCHEDULED");
00813 REG_JUMP("Program Recording Priorities", "", "", startProgramRecPriorities);
00814 REG_JUMP("Channel Recording Priorities", "", "", startChannelRecPriorities);
00815 REG_JUMP("TV Recording Playback", "", "", startPlayback);
00816 REG_JUMP("TV Recording Deletion", "", "", startDelete);
00817 REG_JUMP("Live TV", "", "", startTVNormal);
00818 REG_JUMP("Live TV In Guide", "", "", startTVInGuide);
00819 REG_JUMP("Manual Record Scheduling", "", "", startManual);
00820 REG_JUMP("Status Screen", "", "", showStatus);
00821 REG_JUMP("Previously Recorded", "", "", startPrevious);
00822
00823 REG_KEY("qt", "DELETE", "Delete", "D");
00824 REG_KEY("qt", "EDIT", "Edit", "E");
00825
00826 TV::InitKeys();
00827
00828 TV::SetFuncPtr("playbackbox", (void *)PlaybackBox::RunPlaybackBox);
00829 TV::SetFuncPtr("viewscheduled", (void *)ViewScheduled::RunViewScheduled);
00830 }
00831
00832
00833 void signal_USR1_handler(int){
00834 VERBOSE(VB_GENERAL, "SIG USR1 received, reloading theme");
00835 RemoteSendMessage("CLEAR_SETTINGS_CACHE");
00836 gContext->ActivateSettingsCache(false);
00837 qApp->processEvents();
00838 GetMythMainWindow()->JumpTo("Reload Theme");
00839 gContext->removeCurrentLocation();
00840 gContext->ActivateSettingsCache(true);
00841 }
00842
00843 int internal_media_init()
00844 {
00845 REG_MEDIAPLAYER("Internal", "MythTV's native media player.",
00846 internal_play_media);
00847 return 0;
00848 }
00849
00850 static void *run_priv_thread(void *data)
00851 {
00852 VERBOSE(VB_PLAYBACK, QString("user: %1 effective user: %2 run_priv_thread")
00853 .arg(getuid()).arg(geteuid()));
00854
00855 (void)data;
00856 while (true)
00857 {
00858 gContext->waitPrivRequest();
00859
00860 for (MythPrivRequest req = gContext->popPrivRequest();
00861 true; req = gContext->popPrivRequest())
00862 {
00863 bool done = false;
00864 switch (req.getType())
00865 {
00866 case MythPrivRequest::MythRealtime:
00867 if (gContext->GetNumSetting("RealtimePriority", 1))
00868 {
00869 pthread_t *target_thread = (pthread_t *)(req.getData());
00870
00871 struct sched_param sp = {1};
00872 if (target_thread)
00873 {
00874 int status = pthread_setschedparam(
00875 *target_thread, SCHED_FIFO, &sp);
00876 if (status)
00877 {
00878
00879 VERBOSE(VB_GENERAL, "Realtime priority would require SUID as root.");
00880 }
00881 else
00882 VERBOSE(VB_GENERAL, "Using realtime priority.");
00883 }
00884 else
00885 {
00886 VERBOSE(VB_IMPORTANT, "Unexpected NULL thread ptr "
00887 "for MythPrivRequest::MythRealtime");
00888 }
00889 }
00890 else
00891 VERBOSE(VB_GENERAL, "The realtime priority setting is not enabled.");
00892 break;
00893 case MythPrivRequest::MythExit:
00894 pthread_exit(NULL);
00895 break;
00896 case MythPrivRequest::PrivEnd:
00897 done = true;
00898 break;
00899 }
00900 if (done)
00901 break;
00902 }
00903 }
00904 return NULL;
00905 }
00906
00907 void CleanupMyOldInUsePrograms(void)
00908 {
00909 MSqlQuery query(MSqlQuery::InitCon());
00910
00911 query.prepare("DELETE FROM inuseprograms "
00912 "WHERE hostname = :HOSTNAME and recusage = 'player' ;");
00913 query.bindValue(":HOSTNAME", gContext->GetHostName());
00914 query.exec();
00915 }
00916
00917 void PrintHelp(void)
00918 {
00919
00920 cerr << "Valid options are: " << endl <<
00921 #ifdef USING_X11
00922 "-display X-server Create GUI on X-server, not localhost\n" <<
00923 #endif
00924 "-geometry or --geometry WxH Override window size settings\n" <<
00925 "-geometry WxH+X+Y Override window size and position\n" <<
00926 "-l or --logfile filename Writes STDERR and STDOUT messages to filename" << endl <<
00927 "-r or --reset Resets frontend appearance settings and language" << endl <<
00928 "-w or --windowed Run in windowed mode" << endl <<
00929 "-nw or --no-windowed Run in non-windowed mode " << endl <<
00930 "-O or " << endl <<
00931 " --override-setting KEY=VALUE Force the setting named 'KEY' to value 'VALUE'" << endl <<
00932 " This option may be repeated multiple times" << endl <<
00933 "-G or " << endl <<
00934 " --get-setting KEY[,KEY2,etc] Returns the current database setting for 'KEY'" << endl <<
00935 " Use a comma seperated list to return multiple values" << endl <<
00936 "-v or --verbose debug-level Use '-v help' for level info" << endl <<
00937 "-p or --prompt Always prompt for Mythbackend selection." << endl <<
00938 "-d or --disable-autodiscovery Never prompt for Mythbackend selection." << endl <<
00939
00940 "-u or --upgrade-schema Allow mythfrontend to upgrade the database schema" << endl <<
00941 "--version Version information" << endl <<
00942 "<plugin> Initialize and run this plugin" << endl <<
00943 endl <<
00944 "Environment Variables:" << endl <<
00945 "$MYTHTVDIR Set the installation prefix" << endl <<
00946 "$MYTHCONFDIR Set the config dir (instead of ~/.mythtv)" << endl;
00947
00948 }
00949
00950 int log_rotate(int report_error)
00951 {
00952 int new_logfd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0664);
00953
00954 if (new_logfd < 0) {
00955
00956 if (report_error) {
00957 cerr << "cannot open logfile " << logfile << endl;
00958 return -1;
00959 }
00960
00961 new_logfd = open("/dev/null", O_WRONLY);
00962
00963 if (new_logfd < 0) {
00964
00965 return -1;
00966 }
00967 }
00968
00969 while (dup2(new_logfd, 1) < 0 && errno == EINTR);
00970 while (dup2(new_logfd, 2) < 0 && errno == EINTR);
00971 while (close(new_logfd) < 0 && errno == EINTR);
00972
00973 return 0;
00974 }
00975
00976 void log_rotate_handler(int)
00977 {
00978 log_rotate(0);
00979 }
00980
00981 void CheckSchemaVersion(bool upgradeAllowed)
00982 {
00983 gContext->ActivateSettingsCache(false);
00984 int versionCheck = CompareTVDatabaseSchemaVersion();
00985 bool expertMode = (gContext->GetNumSetting("DBSchemaAutoUpgrade") == -1);
00986
00987 if (versionCheck < 0 && !upgradeAllowed && !expertMode)
00988 {
00989 VERBOSE(VB_IMPORTANT, "Unexpected DB Schema version. Waiting to see "
00990 "if DB is being upgraded.");
00991
00992 bool backupRunning = false;
00993 MythTimer elapsedTimer;
00994 elapsedTimer.start();
00995 while (versionCheck && (elapsedTimer.elapsed() < 5000))
00996 {
00997 sleep(1);
00998
00999 versionCheck = CompareTVDatabaseSchemaVersion();
01000
01001 if (DBUtil::IsBackupInProgress())
01002 {
01003 elapsedTimer.restart();
01004 if (!backupRunning)
01005 {
01006 VERBOSE(VB_IMPORTANT, "Waiting for Database Backup to "
01007 "complete.");
01008 backupRunning = true;
01009 }
01010 }
01011 }
01012
01013 if (versionCheck)
01014 VERBOSE(VB_IMPORTANT, "Timed out waiting.");
01015 else
01016 VERBOSE(VB_IMPORTANT,
01017 "Schema version was upgraded while we were waiting.");
01018 }
01019
01020 if (versionCheck < 0 && !upgradeAllowed && !expertMode)
01021 {
01022 VERBOSE(VB_IMPORTANT, "This version of MythTV requires an updated "
01023 "database schema. Please run mythtv-setup or mythbackend "
01024 "to update your database.");
01025 exit(FRONTEND_EXIT_DB_OUTOFDATE);
01026 }
01027 else if ((versionCheck > 0) && !expertMode)
01028 {
01029 VERBOSE(VB_IMPORTANT, "The schema version of your existing database "
01030 "is newer than this version of MythTV understands. Please "
01031 "ensure that you have selected the proper database server or "
01032 "upgrade this and all other frontends and backends to the "
01033 "same MythTV version and revision.");
01034 exit(FRONTEND_EXIT_DB_OUTOFDATE);
01035 }
01036 if ((upgradeAllowed || expertMode) && !UpgradeTVDatabaseSchema())
01037 {
01038 VERBOSE(VB_IMPORTANT,
01039 "Couldn't upgrade database to new schema, exiting.");
01040 exit(FRONTEND_EXIT_DB_OUTOFDATE);
01041 }
01042 gContext->ActivateSettingsCache(true);
01043 }
01044
01045 int main(int argc, char **argv)
01046 {
01047 bool bPromptForBackend = false;
01048 bool bBypassAutoDiscovery = false;
01049 bool upgradeAllowed = false;
01050
01051 QString geometry = QString::null;
01052 QString display = QString::null;
01053
01054 for(int argpos = 0; argpos < argc; ++argpos)
01055 {
01056 if (!strcmp(argv[argpos],"--version"))
01057 {
01058 extern const char *myth_source_version;
01059 extern const char *myth_source_path;
01060 cout << "Please include all output in bug reports." << endl;
01061 cout << "MythTV Version : " << myth_source_version << endl;
01062 cout << "MythTV Branch : " << myth_source_path << endl;
01063 cout << "Network Protocol : " << MYTH_PROTO_VERSION << endl;
01064 cout << "Library API : " << MYTH_BINARY_VERSION << endl;
01065 #ifdef MYTH_BUILD_CONFIG
01066 cout << "Options compiled in:" <<endl;
01067 cout << MYTH_BUILD_CONFIG << endl;
01068 #endif
01069 return FRONTEND_EXIT_OK;
01070 }
01071 #ifdef USING_X11
01072
01073
01074 else if (!strcmp(argv[argpos],"-geometry"))
01075 geometry = argv[argpos+1];
01076 else if (!strcmp(argv[argpos],"-display"))
01077 display = argv[argpos+1];
01078 #endif // USING_X11
01079 }
01080
01081 #ifdef Q_WS_MACX
01082
01083
01084 QApplication::setDesktopSettingsAware(FALSE);
01085 #endif
01086 QApplication a(argc, argv);
01087
01088 QString pluginname = "";
01089 QMap<QString, QString> settingsOverride;
01090
01091 QFileInfo finfo(a.argv()[0]);
01092
01093 QString binname = finfo.baseName();
01094
01095 bool ResetSettings = false;
01096
01097 if (binname.lower() != "mythfrontend")
01098 pluginname = binname;
01099
01100 for (int argpos = 1; argpos < a.argc(); ++argpos)
01101 {
01102 if (!strcmp(a.argv()[argpos],"-display") ||
01103 !strcmp(a.argv()[argpos],"--display"))
01104 {
01105 if (a.argc()-1 > argpos)
01106 {
01107 display = a.argv()[argpos+1];
01108 if (display.startsWith("-"))
01109 {
01110 cerr << "Invalid or missing argument to -display option\n";
01111 return FRONTEND_EXIT_INVALID_CMDLINE;
01112 }
01113 else
01114 ++argpos;
01115 }
01116 else
01117 {
01118 cerr << "Missing argument to -display option\n";
01119 return FRONTEND_EXIT_INVALID_CMDLINE;
01120 }
01121 }
01122 else if (!strcmp(a.argv()[argpos],"-h") ||
01123 !strcmp(a.argv()[argpos],"--help") ||
01124 !strcmp(a.argv()[argpos],"--usage"))
01125 {
01126 PrintHelp();
01127 return FRONTEND_EXIT_OK;
01128 }
01129 else if (!strcmp(a.argv()[argpos],"--prompt") ||
01130 !strcmp(a.argv()[argpos],"-p" ))
01131 {
01132 bPromptForBackend = true;
01133 }
01134 else if (!strcmp(a.argv()[argpos],"--disable-autodiscovery") ||
01135 !strcmp(a.argv()[argpos],"-d" ))
01136 {
01137 bBypassAutoDiscovery = true;
01138 }
01139 else if (!strcmp(a.argv()[argpos],"--verbose") ||
01140 !strcmp(a.argv()[argpos],"-v"))
01141 {
01142 if (a.argc()-1 > argpos)
01143 {
01144 if (parse_verbose_arg(a.argv()[argpos+1]) ==
01145 GENERIC_EXIT_INVALID_CMDLINE)
01146 return FRONTEND_EXIT_INVALID_CMDLINE;
01147
01148 ++argpos;
01149 } else
01150 {
01151 cerr << "Missing argument to -v/--verbose option\n";
01152 return FRONTEND_EXIT_INVALID_CMDLINE;
01153 }
01154 }
01155 }
01156
01157 if (!display.isEmpty())
01158 {
01159 MythContext::SetX11Display(display);
01160 }
01161
01162 gContext = new MythContext(MYTH_BINARY_VERSION);
01163 g_pUPnp = new MediaRenderer();
01164
01165 if (!gContext->Init(true, g_pUPnp, bPromptForBackend, bBypassAutoDiscovery))
01166 {
01167 VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
01168 return FRONTEND_EXIT_NO_MYTHCONTEXT;
01169 }
01170
01171 for(int argpos = 1; argpos < a.argc(); ++argpos)
01172 {
01173 if (!strcmp(a.argv()[argpos],"-l") ||
01174 !strcmp(a.argv()[argpos],"--logfile"))
01175 {
01176 if (a.argc()-1 > argpos)
01177 {
01178 logfile = a.argv()[argpos+1];
01179 if (logfile.startsWith("-"))
01180 {
01181 cerr << "Invalid or missing argument to -l/--logfile option\n";
01182 return FRONTEND_EXIT_INVALID_CMDLINE;
01183 }
01184 else
01185 {
01186 ++argpos;
01187 }
01188 }
01189 else
01190 {
01191 cerr << "Missing argument to -l/--logfile option\n";
01192 return FRONTEND_EXIT_INVALID_CMDLINE;
01193 }
01194 } else if (!strcmp(a.argv()[argpos],"-v") ||
01195 !strcmp(a.argv()[argpos],"--verbose"))
01196 {
01197
01198 ++argpos;
01199 }
01200 else if (!strcmp(a.argv()[argpos],"-r") ||
01201 !strcmp(a.argv()[argpos],"--reset"))
01202 {
01203 ResetSettings = true;
01204 }
01205 else if (!strcmp(a.argv()[argpos],"-w") ||
01206 !strcmp(a.argv()[argpos],"--windowed"))
01207 {
01208 settingsOverride["RunFrontendInWindow"] = "1";
01209 }
01210 else if (!strcmp(a.argv()[argpos],"-nw") ||
01211 !strcmp(a.argv()[argpos],"--no-windowed"))
01212 {
01213 settingsOverride["RunFrontendInWindow"] = "0";
01214 }
01215 else if (!strcmp(a.argv()[argpos],"-O") ||
01216 !strcmp(a.argv()[argpos],"--override-setting"))
01217 {
01218 if (a.argc()-1 > argpos)
01219 {
01220 QString tmpArg = a.argv()[argpos+1];
01221 if (tmpArg.startsWith("-"))
01222 {
01223 cerr << "Invalid or missing argument to -O/--override-setting option\n";
01224 return BACKEND_EXIT_INVALID_CMDLINE;
01225 }
01226
01227 QStringList pairs = QStringList::split(",", tmpArg);
01228 for (unsigned int index = 0; index < pairs.size(); ++index)
01229 {
01230 QStringList tokens = QStringList::split("=", pairs[index]);
01231 tokens[0].replace(QRegExp("^[\"']"), "");
01232 tokens[0].replace(QRegExp("[\"']$"), "");
01233 tokens[1].replace(QRegExp("^[\"']"), "");
01234 tokens[1].replace(QRegExp("[\"']$"), "");
01235 settingsOverride[tokens[0]] = tokens[1];
01236 }
01237 }
01238 else
01239 {
01240 cerr << "Invalid or missing argument to -O/--override-setting option\n";
01241 return BACKEND_EXIT_INVALID_CMDLINE;
01242 }
01243
01244 ++argpos;
01245 }
01246 else if (!strcmp(a.argv()[argpos],"-G") ||
01247 !strcmp(a.argv()[argpos],"--get-setting"))
01248 {
01249 if (a.argc()-1 > argpos)
01250 {
01251 QString tmpArg = a.argv()[argpos+1];
01252 if (tmpArg.startsWith("-"))
01253 {
01254 cerr << "Invalid or missing argument to -G/--get-setting option\n";
01255 return FRONTEND_EXIT_INVALID_CMDLINE;
01256 }
01257
01258 QStringList pairs = QStringList::split(",", tmpArg);
01259 QString value;
01260 for (unsigned int index = 0; index < pairs.size(); ++index)
01261 {
01262 value = gContext->GetSetting(pairs[index]);
01263 cout << "\tSettings Value : " << pairs[index];
01264 cout << " = " << value << endl;
01265 }
01266 return FRONTEND_EXIT_OK;
01267 }
01268 else
01269 {
01270 cerr << "Invalid or missing argument to -G/--get-setting option\n";
01271 return FRONTEND_EXIT_INVALID_CMDLINE;
01272 }
01273
01274 ++argpos;
01275 }
01276 else if (!strcmp(a.argv()[argpos],"-geometry") ||
01277 !strcmp(a.argv()[argpos],"--geometry"))
01278 {
01279 if (a.argc()-1 > argpos)
01280 {
01281 geometry = a.argv()[argpos+1];
01282 if (geometry.startsWith("-"))
01283 {
01284 cerr << "Invalid or missing argument to -geometry option\n";
01285 return FRONTEND_EXIT_INVALID_CMDLINE;
01286 }
01287 else
01288 ++argpos;
01289 }
01290 else
01291 {
01292 cerr << "Missing argument to -geometry option\n";
01293 return FRONTEND_EXIT_INVALID_CMDLINE;
01294 }
01295 }
01296 else if (!strcmp(a.argv()[argpos],"--prompt") ||
01297 !strcmp(a.argv()[argpos],"-p" ))
01298 {
01299 }
01300 else if (!strcmp(a.argv()[argpos],"--disable-autodiscovery") ||
01301 !strcmp(a.argv()[argpos],"-d" ))
01302 {
01303 }
01304 else if (!strcmp(a.argv()[argpos],"--upgrade-schema") ||
01305 !strcmp(a.argv()[argpos],"-u" ))
01306 {
01307 upgradeAllowed = true;
01308 }
01309 else if ((argpos + 1 == a.argc()) &&
01310 !QString(a.argv()[argpos]).startsWith("-"))
01311 {
01312 pluginname = a.argv()[argpos];
01313 }
01314 else
01315 {
01316 if (!(!strcmp(a.argv()[argpos],"-h") ||
01317 !strcmp(a.argv()[argpos],"--help") ||
01318 !strcmp(a.argv()[argpos],"--usage")))
01319 cerr << "Invalid argument: " << a.argv()[argpos] << endl;
01320 PrintHelp();
01321 return FRONTEND_EXIT_INVALID_CMDLINE;
01322 }
01323 }
01324
01325 int pa_ret = pulseaudio_handle_startup();
01326 if (pa_ret != GENERIC_EXIT_OK)
01327 return pa_ret;
01328
01329 if (logfile != "")
01330 {
01331 if (log_rotate(1) < 0)
01332 cerr << "cannot open logfile; using stdout/stderr" << endl;
01333 else
01334 signal(SIGHUP, &log_rotate_handler);
01335 }
01336
01337 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
01338 cerr << "Unable to ignore SIGPIPE\n";
01339
01340 QString fileprefix = MythContext::GetConfDir();
01341
01342 QDir dir(fileprefix);
01343 if (!dir.exists())
01344 dir.mkdir(fileprefix);
01345
01346 if (ResetSettings)
01347 {
01348 AppearanceSettings as;
01349 as.save();
01350
01351 MSqlQuery query(MSqlQuery::InitCon());
01352 query.prepare("update settings set data='EN' "
01353 "WHERE hostname = :HOSTNAME and value='Language' ;");
01354 query.bindValue(":HOSTNAME", gContext->GetHostName());
01355 query.exec();
01356
01357 return FRONTEND_EXIT_OK;
01358 }
01359
01360 if (!geometry.isEmpty() && !gContext->ParseGeometryOverride(geometry))
01361 {
01362 VERBOSE(VB_IMPORTANT,
01363 QString("Illegal -geometry argument '%1' (ignored)")
01364 .arg(geometry));
01365 }
01366
01367 if (settingsOverride.size())
01368 {
01369 QMap<QString, QString>::iterator it;
01370 for (it = settingsOverride.begin(); it != settingsOverride.end(); ++it)
01371 {
01372 VERBOSE(VB_IMPORTANT, QString("Setting '%1' being forced to '%2'")
01373 .arg(it.key()).arg(it.data()));
01374 gContext->OverrideSettingForSession(it.key(), it.data());
01375 }
01376 }
01377
01378
01379 pthread_t priv_thread;
01380 bool priv_thread_created = true;
01381
01382 VERBOSE(VB_PLAYBACK, QString("user: %1 effective user: %2 before "
01383 "privileged thread").arg(getuid()).arg(geteuid()));
01384 int status = pthread_create(&priv_thread, NULL, run_priv_thread, NULL);
01385 VERBOSE(VB_PLAYBACK, QString("user: %1 effective user: %2 after "
01386 "privileged thread").arg(getuid()).arg(geteuid()));
01387 if (status)
01388 {
01389 VERBOSE(VB_IMPORTANT, QString("Warning: ") +
01390 "Failed to create priveledged thread." + ENO);
01391 priv_thread_created = false;
01392 }
01393 setuid(getuid());
01394
01395 CheckSchemaVersion(upgradeAllowed);
01396
01397 VERBOSE(VB_IMPORTANT, QString("%1 version: %2 www.mythtv.org")
01398 .arg(binname).arg(MYTH_BINARY_VERSION));
01399
01400 VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1").arg(verboseString));
01401
01402 LCD::SetupLCD();
01403 if (LCD *lcd = LCD::Get())
01404 lcd->setupLEDs(RemoteGetRecordingMask);
01405
01406 LanguageSettings::load("mythfrontend");
01407
01408 WriteDefaults();
01409
01410 QString themename = gContext->GetSetting("Theme", "G.A.N.T");
01411 bool randomtheme = gContext->GetNumSetting("RandomTheme", 0);
01412
01413 if (randomtheme)
01414 themename = RandTheme(themename);
01415
01416 QString themedir = gContext->FindThemeDir(themename);
01417 if (themedir == "")
01418 {
01419 cerr << "Couldn't find theme " << themename << endl;
01420 return FRONTEND_EXIT_NO_THEME;
01421 }
01422
01423 gContext->LoadQtConfig();
01424
01425 MythMainWindow *mainWindow = GetMythMainWindow();
01426 mainWindow->Init();
01427 gContext->SetMainWindow(mainWindow);
01428
01429 gContext->UpdateImageCache();
01430 themeBase = new MythThemeBase();
01431
01432 LanguageSettings::prompt();
01433
01434 InitJumpPoints();
01435
01436 internal_media_init();
01437
01438 CleanupMyOldInUsePrograms();
01439
01440 MythPluginManager *pmanager = new MythPluginManager();
01441 gContext->SetPluginManager(pmanager);
01442
01443 if (gContext->GetNumSetting("EnableXbox") == 1)
01444 {
01445 xbox = new XBox();
01446 xbox->GetSettings();
01447 }
01448 else
01449 xbox = NULL;
01450
01451
01452
01453 if (gContext->GetNumSetting("idleTimeoutSecs",0) > 0)
01454 gContext->ConnectToMasterServer();
01455
01456 qApp->lock();
01457
01458 if (pluginname != "")
01459 {
01460 if (pmanager->run_plugin(pluginname))
01461 {
01462 qApp->setMainWidget(mainWindow);
01463 qApp->exec();
01464
01465 qApp->unlock();
01466 return FRONTEND_EXIT_OK;
01467 }
01468 else
01469 {
01470 pluginname = "myth" + pluginname;
01471 if (pmanager->run_plugin(pluginname))
01472 {
01473 qApp->setMainWidget(mainWindow);
01474 qApp->exec();
01475
01476 qApp->unlock();
01477 return FRONTEND_EXIT_OK;
01478 }
01479 }
01480 }
01481
01482 qApp->unlock();
01483
01484 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
01485 if (mon)
01486 mon->StartMonitoring();
01487
01488 NetworkControl *networkControl = NULL;
01489 if (gContext->GetNumSetting("NetworkControlEnabled", 0))
01490 {
01491 int networkPort = gContext->GetNumSetting("NetworkControlPort", 6545);
01492 networkControl = new NetworkControl(networkPort);
01493 if (!networkControl->ok())
01494 VERBOSE(VB_IMPORTANT,
01495 QString("NetworkControl failed to bind to port %1.")
01496 .arg(networkPort));
01497 }
01498
01499 gContext->addCurrentLocation("MainMenu");
01500
01501 int exitstatus = NO_EXIT;
01502
01503 do
01504 {
01505 themename = gContext->GetSetting("Theme", "blue");
01506 themedir = gContext->FindThemeDir(themename);
01507 if (themedir == "")
01508 {
01509 cerr << "Couldn't find theme " << themename << endl;
01510 return FRONTEND_EXIT_NO_THEME;
01511 }
01512
01513 if (!RunMenu(themedir))
01514 break;
01515
01516
01517 signal(SIGUSR1, &signal_USR1_handler);
01518
01519 qApp->setMainWidget(mainWindow);
01520 qApp->exec();
01521 } while (!(exitstatus = handleExit()));
01522
01523 if (exitstatus == HALT)
01524 haltnow();
01525
01526 if (exitstatus == REBOOT)
01527 rebootnow();
01528
01529 pmanager->DestroyAllPlugins();
01530
01531 if (mon)
01532 {
01533 mon->StopMonitoring();
01534 delete mon;
01535 }
01536
01537 if (priv_thread_created)
01538 {
01539 void *value;
01540 gContext->addPrivRequest(MythPrivRequest::MythExit, NULL);
01541 pthread_join(priv_thread, &value);
01542 }
01543
01544 signal(SIGHUP, SIG_DFL);
01545
01546 if (networkControl)
01547 delete networkControl;
01548
01549 DestroyMythMainWindow();
01550 delete themeBase;
01551 delete gContext;
01552
01553 VERBOSE(VB_GENERAL, "Deleting UPnP client...");
01554 delete g_pUPnp;
01555
01556 pa_ret = pulseaudio_handle_teardown();
01557 if (GENERIC_EXIT_OK != pa_ret)
01558 return pa_ret;
01559
01560 return FRONTEND_EXIT_OK;
01561
01562 }
01563