diff --git a/mythtv/libs/libmythui/lirc.cpp b/mythtv/libs/libmythui/lirc.cpp index 843f622c1e5..c4411569acc 100644 --- a/mythtv/libs/libmythui/lirc.cpp +++ b/mythtv/libs/libmythui/lirc.cpp @@ -1,164 +1,568 @@ -#include -#include -#include +// System headers +#include +// C headers #include #include -#include -#include -#include -#include +#include + +// C++ headers +#include +#include +using namespace std; + +// Qt headers +#include +#include +#include +#include +// MythTV headers #include "mythverbose.h" #include "mythdb.h" #include "mythsystem.h" - #include "lirc.h" #include "lircevent.h" -LircThread::LircThread(QObject *main_window) +// POSIX headers +namespace POSIX +{ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +}; +using namespace POSIX; + +#define LOC QString("LIRC: ") +#define LOC_WARN QString("LIRC, Warning: ") +#define LOC_ERR QString("LIRC, Error: ") + +class LIRCPriv +{ + public: + LIRCPriv() : lircConfig(NULL) {} + ~LIRCPriv() + { + if (lircConfig) + { + lirc_freeconfig(lircConfig); + lircConfig = NULL; + } + } + + struct lirc_config *lircConfig; +}; + +QMutex LIRC::lirclib_lock; + +/** \class LIRC + * \brief Interface between mythtv and lircd + * + * Create connection to the lircd daemon and translate remote keypresses + * into custom events which are posted to the mainwindow. + */ + +LIRC::LIRC(QObject *main_window, + const QString &lircd_device, + const QString &our_program, + const QString &config_file, + const QString &external_app) : QThread(), - m_lircConfig(NULL), m_mainWindow(main_window), - m_bStop(false), m_fd(-1), - m_externalApp("") + lock(QMutex::Recursive), + m_mainWindow(main_window), + lircdDevice(lircd_device), + program(our_program), + configFile(config_file), + m_externalApp(external_app), + doRun(false), + lircd_socket(-1), + buf_offset(0), + eofCount(0), + retryCount(0), + d(new LIRCPriv()) +{ + lircdDevice.detach(); + program.detach(); + configFile.detach(); + m_externalApp.detach(); + buf.resize(128); +} + +LIRC::~LIRC() { + TeardownAll(); } -/** - * \brief Initialise the class variables, read the lirc config and user - * settings - */ -int LircThread::Init(const QString &config_file, const QString &program, - bool ignoreExtApp) +void LIRC::deleteLater(void) { - /* Connect the unix socket */ - m_fd = lirc_init((char *)qPrintable(program), 1); - if (m_fd == -1) + TeardownAll(); + QThread::deleteLater(); +} + +void LIRC::TeardownAll(void) +{ + QMutexLocker locker(&lock); + if (doRun) { - VERBOSE(VB_IMPORTANT, - QString("lirc_init failed for %1, see preceding messages") - .arg(program)); - return -1; + doRun = false; + lock.unlock(); + wait(); + lock.lock(); + } + + if (lircd_socket >= 0) + { + close(lircd_socket); + lircd_socket = -1; + } + + if (d) + { + delete d; + d = NULL; + } +} + +QByteArray get_ip(const QString &h) +{ + QByteArray hba = h.toLatin1(); + struct in_addr sin_addr; + if (inet_aton(hba.constData(), &sin_addr)) + return hba; + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo *result; + int err = getaddrinfo(hba.constData(), NULL, &hints, &result); + if (err) + { + VERBOSE(VB_IMPORTANT, QString("get_ip: %1").arg(gai_strerror(err))); + return QString("").toLatin1(); } - /* parse the config file */ - if (lirc_readconfig((char *)qPrintable(config_file), &m_lircConfig, NULL)) + int addrlen = result->ai_addrlen; + if (!addrlen) { - VERBOSE(VB_IMPORTANT, - QString("Failed to read lirc config %1 for %2") - .arg(config_file).arg(program)); - lirc_deinit(); - return -1; + freeaddrinfo(result); + return QString("").toLatin1(); + } + + if (result->ai_addr->sa_family != AF_INET) + { + freeaddrinfo(result); + return QString("").toLatin1(); + } + + sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr; + hba = QByteArray(inet_ntoa(sin_addr)); + freeaddrinfo(result); + + return hba; +} + +bool LIRC::Init(void) +{ + QMutexLocker locker(&lock); + if (lircd_socket >= 0) + return true; + + if (lircdDevice.startsWith('/')) + { + // Connect the unix socket + QByteArray dev = lircdDevice.toLocal8Bit(); + if (dev.size() > 107) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + QString("lircdDevice '%1'") + .arg(lircdDevice) + + " is too long for the 'unix' socket API"); + + return false; + } + + lircd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (lircd_socket < 0) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to open Unix socket '%1'") + .arg(lircdDevice) + ENO); + + return false; + } + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, dev.constData(),107); + + int ret = POSIX::connect( + lircd_socket, (struct sockaddr*) &addr, sizeof(addr)); + + if (ret < 0) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to connect to Unix socket '%1'") + .arg(lircdDevice) + ENO); + + close(lircd_socket); + lircd_socket = -1; + return false; + } + } + else + { + lircd_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (lircd_socket < 0) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to open TCP socket '%1'") + .arg(lircdDevice) + ENO); + + return false; + } + + QString dev = lircdDevice; + uint port = 8765; + QStringList tmp = lircdDevice.split(':'); + if (2 == tmp.size()) + { + dev = tmp[0]; + port = (tmp[1].toUInt()) ? tmp[1].toUInt() : port; + } + QByteArray device = get_ip(dev); + struct sockaddr_in addr; + memset(&addr, 0, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (!inet_aton(device.constData(), &addr.sin_addr)) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to parse IP address '%1'").arg(dev)); + + close(lircd_socket); + lircd_socket = -1; + return false; + } + + int ret = POSIX::connect( + lircd_socket, (struct sockaddr*) &addr, sizeof(addr)); + if (ret < 0) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to connect TCP socket '%1'") + .arg(lircdDevice) + ENO); + + close(lircd_socket); + lircd_socket = -1; + return false; + } + + // On Linux, select() can indicate data when there isn't + // any due to TCP checksum in-particular; to avoid getting + // stuck on a read() call add the O_NONBLOCK flag. + int flags = fcntl(lircd_socket, F_GETFD); + if (flags >= 0) + { + ret = fcntl(lircd_socket, F_SETFD, flags | O_NONBLOCK); + if (ret < 0) + { + VERBOSE(VB_IMPORTANT, LOC_WARN + + QString("Failed set flags for socket '%1'") + .arg(lircdDevice) + ENO); + } + } + + // Attempt to inline out-of-band messages and keep the connection open.. + int i = 1; + setsockopt(lircd_socket, SOL_SOCKET, SO_OOBINLINE, &i, sizeof(i)); + i = 1; + setsockopt(lircd_socket, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i)); + } + + // parse the config file + if (!d->lircConfig) + { + QMutexLocker static_lock(&lirclib_lock); + QByteArray cfg = configFile.toLocal8Bit(); + if (lirc_readconfig( + const_cast(cfg.constData()), &d->lircConfig, NULL)) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + QString("Failed to read config file '%1'").arg(configFile)); + + close(lircd_socket); + lircd_socket = -1; + return false; + } + + // Get rid of the stuff we don't care about.. + vector del; + struct lirc_config_entry *it = d->lircConfig->first; + while (it->next) + { + if (program == QString(it->next->prog)) + { + it = it->next; + } + else + { + del.push_back(it->next); + it->next = it->next->next; + } + } + if (program != QString(d->lircConfig->first->prog)) + { + del.push_back(d->lircConfig->first); + d->lircConfig->first = d->lircConfig->first->next; + } + d->lircConfig->next = d->lircConfig->first; + + for (uint i = 0; i < del.size(); i++) + { + struct lirc_config_entry *c = del[i]; + if (c->prog) + free(c->prog); + if (c->change_mode) + free(c->change_mode); + if (c->mode) + free(c->mode); + + struct lirc_code *code = c->code; + while (code) + { + if (code->remote && code->remote!=LIRC_ALL) + free(code->remote); + if (code->button && code->button!=LIRC_ALL) + free(code->button); + struct lirc_code *code_temp = code->next; + free(code); + code = code_temp; + } + + struct lirc_list *list = c->config; + while (list) + { + if (list->string) + free(list->string); + struct lirc_list *list_temp = list->next; + free(list); + list = list_temp; + } + + free(c); + } } + + VERBOSE(VB_GENERAL, LOC + + QString("Successfully initialized '%1' using '%2' config") + .arg(lircdDevice).arg(configFile)); + + return true; +} - if (!ignoreExtApp) - m_externalApp = GetMythDB()->GetSetting("LircKeyPressedApp", ""); +void LIRC::start(void) +{ + QMutexLocker locker(&lock); - VERBOSE(VB_GENERAL, - QString("lirc init success using configuration file: %1") - .arg(config_file)); + if (lircd_socket < 0) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + "start() called without lircd socket"); + return; + } - return 0; + doRun = true; + QThread::start(); } -LircThread::~LircThread() +bool LIRC::IsDoRunSet(void) const { - lirc_deinit(); - if (m_lircConfig) - lirc_freeconfig(m_lircConfig); + QMutexLocker locker(&lock); + return doRun; } -/** - * \brief Main thread loop - */ -void LircThread::run(void) +void LIRC::Process(const QByteArray &data) { - char *code = 0; - char *ir = 0; - int ret; - fd_set readfds; - struct timeval timeout; + QMutexLocker static_lock(&lirclib_lock); + + // lirc_code2char will make code point to a static datafer.. + char *code = NULL; + int ret = lirc_code2char( + d->lircConfig, const_cast(data.constData()), &code); + + while ((0 == ret) && code) + { + QString text(code); + QKeySequence a(code); + + int keycode = 0; + + // Send a dummy keycode if we couldn't convert the key sequence. + // This is done so the main code can output a warning for bad + // mappings. + if (!a.count()) + { + QApplication::postEvent( + m_mainWindow, new LircKeycodeEvent(text, keycode, true)); + } + + for (unsigned int i = 0; i < a.count(); i++) + { + keycode = a[i]; + + QApplication::postEvent( + m_mainWindow, new LircKeycodeEvent(text, keycode, true)); + QApplication::postEvent( + m_mainWindow, new LircKeycodeEvent(text, keycode, false)); + + SpawnApp(); + } + ret = lirc_code2char( + d->lircConfig, const_cast(data.constData()), &code); + } +} +void LIRC::run(void) +{ + //VERBOSE(VB_GENERAL, LOC + "run -- start"); /* Process all events read */ - while (!m_bStop) + while (IsDoRunSet()) { + if (eofCount && retryCount) + usleep(100 * 1000); + + if ((eofCount >= 10) || (lircd_socket < 0)) + { + QMutexLocker locker(&lock); + eofCount = 0; + if (++retryCount > 1000) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + + "Failed to reconnect, exiting LIRC thread."); + doRun = false; + continue; + } + VERBOSE(VB_GENERAL, LOC_WARN + "EOF -- reconnecting"); + + close(lircd_socket); + lircd_socket = -1; + + if (!Init()) + sleep(2); // wait a while before we retry.. + + continue; + } + + fd_set readfds; FD_ZERO(&readfds); - FD_SET(m_fd, &readfds); + FD_SET(lircd_socket, &readfds); // the maximum time select() should wait - timeout.tv_sec = 0; - timeout.tv_usec = 100000; + struct timeval timeout; + timeout.tv_sec = 1; // 1 second + timeout.tv_usec = 100 * 1000; // 100 ms + + int ret = select(lircd_socket + 1, &readfds, NULL, NULL, &timeout); - ret = select(m_fd + 1, &readfds, NULL, NULL, &timeout); + if (ret < 0 && errno != EINTR) + { + VERBOSE(VB_IMPORTANT, LOC_ERR + "select() failed" + ENO); + continue; + } - if (ret == 0) + // 0: Timer expired with no data, repeat select + // -1: Iinterrupted while waiting, repeat select + if (ret <= 0) continue; - if (ret == -1) + QList codes = GetCodes(); + for (uint i = 0; i < (uint) codes.size(); i++) + Process(codes[i]); + } + //VERBOSE(VB_GENERAL, LOC + "run -- end"); +} + +QList LIRC::GetCodes(void) +{ + QList ret; + ssize_t len = -1; + + while (true) + { + len = read(lircd_socket, + buf.data() + buf_offset, + buf.size() - buf_offset - 1); + + if (len >= 0) + break; + + if (EINTR == errno) + continue; + else if (EAGAIN == errno) + return ret; + else if (107 == errno) { - perror("LircThread - select"); - return; + if (!eofCount) + VERBOSE(VB_GENERAL, LOC + "GetCodes -- EOF?"); + eofCount++; + return ret; } - - if (ret == 1) + else { - ret = lirc_nextcode(&ir); + VERBOSE(VB_IMPORTANT, LOC + "Error reading socket" + ENO); + return ret; + } - if (ret == -1) - { - if (errno != 0) - VERBOSE(VB_IMPORTANT, - QString("LircThread: lirc_nextcode failed" - "last error was: %1").arg(errno)); - return; - } + break; + } - if (!ir) - continue; + if (0 == len) + { + if (!eofCount) + VERBOSE(VB_GENERAL, LOC + "GetCodes -- eof?"); + eofCount++; + return ret; + } - while ((ret = lirc_code2char(m_lircConfig, ir, &code)) == 0 && - code != NULL) - { - QKeySequence a(code); - - int keycode = 0; - - // Send a dummy keycode if we couldn't convert the key sequence. - // This is done so the main code can output a warning for bad - // mappings. - if (!a.count()) - QApplication::postEvent(m_mainWindow, - new LircKeycodeEvent(code, keycode, - true)); - - for (unsigned int i = 0; i < a.count(); i++) - { - keycode = a[i]; - - QApplication::postEvent(m_mainWindow, - new LircKeycodeEvent(code, keycode, - true)); - QApplication::postEvent(m_mainWindow, - new LircKeycodeEvent(code, keycode, - false)); - - SpawnApp(); - } - } + eofCount = 0; + retryCount = 0; - free(ir); - if (ret == -1) - break; - } + buf_offset += len; + if ((uint)buf.size() < buf_offset + 128) + buf.reserve(buf.size() * 2); + uint tmpc = std::max(buf.capacity() - 1,128); + + buf.resize(buf_offset); + ret = buf.split('\n'); + buf.resize(tmpc); + if (buf.endsWith('\n')) + { + buf_offset = 0; + return ret; } + + buf = ret.back(); + ret.pop_back(); + buf_offset = std::max(buf.size() - 1, 0); + buf.resize(tmpc); + + return ret; } -/** - * \brief Spawn a user defined application which might do something like - * illuminating an led to give positive feedback that a key was received - */ -void LircThread::SpawnApp(void) +void LIRC::SpawnApp(void) { + // Spawn app to illuminate led (or what ever the user has picked if + // anything) to give positive feedback that a key was received if (m_externalApp.isEmpty()) return; diff --git a/mythtv/libs/libmythui/lirc.h b/mythtv/libs/libmythui/lirc.h index ac59cb3ed14..ddd23b8683d 100644 --- a/mythtv/libs/libmythui/lirc.h +++ b/mythtv/libs/libmythui/lirc.h @@ -1,37 +1,53 @@ #ifndef LIRC_H_ #define LIRC_H_ -#include +#include #include +#include +#include +#include +#include -#include +class LIRCPriv; -/** \class LircThread - * \brief Interface between mythtv and lircd - * - * Create connection to the lircd daemon and translate remote keypresses - * into custom events which are posted to the mainwindow. - */ -class LircThread : public QThread +class LIRC : public QThread { Q_OBJECT public: - LircThread(QObject *main_window); - ~LircThread(); - int Init(const QString &config_file, const QString &program, - bool ignoreExtApp=false); - void Stop(void) { m_bStop = true; } + LIRC(QObject *main_window, + const QString &lircd_device, + const QString &our_program, + const QString &config_file, + const QString &external_app); + bool Init(void); - private: - void run(void); - void SpawnApp(void); + virtual void start(void); + virtual void deleteLater(void); - struct lirc_config *m_lircConfig; - QObject *m_mainWindow; - volatile bool m_bStop; - int m_fd; + private: + virtual ~LIRC(); + void TeardownAll(); - QString m_externalApp; + bool IsDoRunSet(void) const; + virtual void run(void); + void SpawnApp(void); + QList GetCodes(void); + void Process(const QByteArray &data); + + mutable QMutex lock; + static QMutex lirclib_lock; + QObject *m_mainWindow; ///< window to send key events to + QString lircdDevice; ///< device on which to receive lircd data + QString program; ///< program to extract from config file + QString configFile; ///< file containing LIRC->key mappings + QString m_externalApp; ///< external application for keys + bool doRun; + int lircd_socket; + uint buf_offset; + QByteArray buf; + uint eofCount; + uint retryCount; + LIRCPriv *d; }; #endif diff --git a/mythtv/libs/libmythui/lircevent.cpp b/mythtv/libs/libmythui/lircevent.cpp index 04364ba730c..5c145b83e3a 100644 --- a/mythtv/libs/libmythui/lircevent.cpp +++ b/mythtv/libs/libmythui/lircevent.cpp @@ -4,8 +4,8 @@ #include "mythmainwindow.h" #include "lircevent.h" -LircEventLock::LircEventLock(bool lock_events) - : m_eventsLocked(false) +LircEventLock::LircEventLock(bool lock_events) + : events_locked(false) { if (lock_events) lock(); @@ -13,7 +13,7 @@ LircEventLock::LircEventLock(bool lock_events) LircEventLock::~LircEventLock() { - if (m_eventsLocked) + if (events_locked) unlock(); } @@ -22,9 +22,9 @@ void LircEventLock::lock() MythMainWindow *mw = GetMythMainWindow(); if (mw) { - m_eventsLocked = true; + events_locked = true; QApplication::postEvent((QObject *)mw, - new LircMuteEvent(m_eventsLocked)); + new LircMuteEvent(events_locked)); } } @@ -33,8 +33,8 @@ void LircEventLock::unlock() MythMainWindow *mw = GetMythMainWindow(); if (mw) { - m_eventsLocked = false; + events_locked = false; QApplication::postEvent((QObject *)mw, - new LircMuteEvent(m_eventsLocked)); + new LircMuteEvent(events_locked)); } } diff --git a/mythtv/libs/libmythui/lircevent.h b/mythtv/libs/libmythui/lircevent.h index 362375c4003..fdf0d688d49 100644 --- a/mythtv/libs/libmythui/lircevent.h +++ b/mythtv/libs/libmythui/lircevent.h @@ -47,7 +47,7 @@ class LircEventLock void unlock(); private: - bool m_eventsLocked; + bool events_locked; }; #endif diff --git a/mythtv/libs/libmythui/mythmainwindow.cpp b/mythtv/libs/libmythui/mythmainwindow.cpp index 8f3322cbf2b..c5271b7d131 100644 --- a/mythtv/libs/libmythui/mythmainwindow.cpp +++ b/mythtv/libs/libmythui/mythmainwindow.cpp @@ -24,14 +24,11 @@ #include // For GetMBarHeight() #endif -#ifdef USE_LIRC #include "lirc.h" #include "lircevent.h" -#endif #ifdef USING_APPLEREMOTE #include "AppleRemoteListener.h" -#include "lircevent.h" #endif #ifdef USE_JOYSTICK_MENU @@ -118,9 +115,7 @@ class MythMainWindowPrivate bool ignore_lirc_keys; bool ignore_joystick_keys; -#ifdef USE_LIRC - LircThread *lircThread; -#endif + LIRC *lircThread; #ifdef USE_JOYSTICK_MENU JoystickMenuThread *joystickThread; @@ -336,16 +331,8 @@ MythMainWindow::MythMainWindow(const bool useDB) installEventFilter(this); -#ifdef USE_LIRC - QString config_file = GetConfDir() + "/lircrc"; - if (!QFile::exists(config_file)) - config_file = QDir::homePath() + "/.lircrc"; - d->lircThread = NULL; - d->lircThread = new LircThread(this); - if (!d->lircThread->Init(config_file, "mythtv")) - d->lircThread->start(); -#endif + StartLIRC(); #ifdef USE_JOYSTICK_MENU d->ignore_joystick_keys = false; @@ -449,13 +436,7 @@ MythMainWindow::~MythMainWindow() #ifdef USE_LIRC if (d->lircThread) { - if (d->lircThread->isRunning()) - { - d->lircThread->Stop(); - d->lircThread->wait(); - } - - delete d->lircThread; + d->lircThread->deleteLater(); d->lircThread = NULL; } #endif @@ -1762,4 +1743,35 @@ QRect MythMainWindow::GetUIScreenRect(void) return d->uiScreenRect; } +void MythMainWindow::StartLIRC(void) +{ +#ifdef USE_LIRC + if (d->lircThread) + { + d->lircThread->deleteLater(); + d->lircThread = NULL; + } + + QString config_file = GetConfDir() + "/lircrc"; + if (!QFile::exists(config_file)) + config_file = QDir::homePath() + "/.lircrc"; + + d->lircThread = new LIRC( + this, + GetMythDB()->GetSetting("LircSocket", "/dev/lircd"), + "mythtv", config_file, + GetMythDB()->GetSetting("LircKeyPressedApp", "")); + + if (d->lircThread->Init()) + { + d->lircThread->start(); + } + else + { + d->lircThread->deleteLater(); + d->lircThread = NULL; + } +#endif +} + /* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythui/mythmainwindow.h b/mythtv/libs/libmythui/mythmainwindow.h index 4d77890f85b..80a875eb0fb 100644 --- a/mythtv/libs/libmythui/mythmainwindow.h +++ b/mythtv/libs/libmythui/mythmainwindow.h @@ -95,6 +95,8 @@ class MPUBLIC MythMainWindow : public QWidget int NormY(const int y); int fonTweak; + void StartLIRC(void); + /* compatability functions, to go away once everything's mythui */ void attach(QWidget *child); void detach(QWidget *child); diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp index 2ebad9ee4a5..98d723fbf47 100644 --- a/mythtv/programs/mythfrontend/globalsettings.cpp +++ b/mythtv/programs/mythfrontend/globalsettings.cpp @@ -2313,10 +2313,22 @@ static HostLineEdit *HaltCommand() return ge; } +static HostLineEdit *LircDaemonDevice() +{ + HostLineEdit *ge = new HostLineEdit("LircSocket"); + ge->setLabel(QObject::tr("LIRC Daemon Socket")); + ge->setValue("/dev/lircd"); + QString help = QObject::tr( + "UNIX socket or IP address[:port] to connect in " + "order to communicate with the LIRC Daemon."); + ge->setHelpText(help); + return ge; +} + static HostLineEdit *LircKeyPressedApp() { HostLineEdit *ge = new HostLineEdit("LircKeyPressedApp"); - ge->setLabel(QObject::tr("Keypress Application")); + ge->setLabel(QObject::tr("LIRC Keypress Application")); ge->setValue(""); ge->setHelpText(QObject::tr("External application or script to run when " "a keypress is received by LIRC.")); @@ -2326,7 +2338,7 @@ static HostLineEdit *LircKeyPressedApp() static HostLineEdit *ScreenShotPath() { HostLineEdit *ge = new HostLineEdit("ScreenShotPath"); - ge->setLabel(QObject::tr("ScreenShotPath")); + ge->setLabel(QObject::tr("Screen Shot Path")); ge->setValue("/tmp/"); ge->setHelpText(QObject::tr("Path to screenshot storage location. Should be writable by the frontend")); return ge; @@ -4630,10 +4642,7 @@ MainGeneralSettings::MainGeneralSettings() general->setLabel(QObject::tr("General")); general->addChild(UseArrowAccels()); general->addChild(EnableXbox()); - general->addChild(LircKeyPressedApp()); general->addChild(ScreenShotPath()); - general->addChild(NetworkControlEnabled()); - general->addChild(NetworkControlPort()); addChild(general); VerticalConfigurationGroup *media = @@ -4660,6 +4669,15 @@ MainGeneralSettings::MainGeneralSettings() exit->addChild(shutdownSettings); addChild(exit); + VerticalConfigurationGroup *remotecontrol = + new VerticalConfigurationGroup(false, true, false, false); + remotecontrol->setLabel(QObject::tr("Remote Control")); + remotecontrol->addChild(LircDaemonDevice()); + remotecontrol->addChild(LircKeyPressedApp()); + remotecontrol->addChild(NetworkControlEnabled()); + remotecontrol->addChild(NetworkControlPort()); + addChild(remotecontrol); + MythLogSettings *mythlog = new MythLogSettings(); addChild(mythlog); diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp index 96ffaeb58dd..5e1ae9a4ca5 100644 --- a/mythtv/programs/mythfrontend/main.cpp +++ b/mythtv/programs/mythfrontend/main.cpp @@ -806,6 +806,13 @@ void signal_USR1_handler(int){ gContext->ActivateSettingsCache(true); } +void signal_USR2_handler(int) +{ + VERBOSE(VB_GENERAL, "SIG USR2 received, restart LIRC handler"); + GetMythMainWindow()->StartLIRC(); +} + + int internal_media_init() { REG_MEDIAPLAYER("Internal", "MythTV's native media player.", @@ -1341,6 +1348,8 @@ int main(int argc, char **argv) // Setup handler for USR1 signals to reload theme signal(SIGUSR1, &signal_USR1_handler); + // Setup handler for USR2 signals to restart LIRC + signal(SIGUSR2, &signal_USR2_handler); qApp->exec();