Ticket #9090: mythgame-remote-launch.patch

File mythgame-remote-launch.patch, 15.2 KB (added by James P. Barrett <james.barrett@…>, 9 years ago)
  • mythplugins/mythgame/mythgame/gamehandler.cpp

    diff --git a/mythplugins/mythgame/mythgame/gamehandler.cpp b/mythplugins/mythgame/mythgame/gamehandler.cpp
    index 7a93ea8..ac19efc 100644
    a b  
    66#include <QRegExp>
    77#include <QDir>
    88#include <QList>
     9#include <QMutex>
    910
    1011#include <mythcontext.h>
    1112#include <mythdbcon.h>
     
    1819#define LOC QString("MythGame:GAMEHANDLER: ")
    1920
    2021static QList<GameHandler*> *handlers = NULL;
     22static QMutex *game_launch_mutex = NULL;
    2123
    2224bool existsHandler(const QString name)
    2325{
    GameHandler* GameHandler::GetHandlerByName(QString systemname) 
    823825
    824826void GameHandler::Launchgame(RomInfo *romdata, QString systemname)
    825827{
    826     GameHandler *handler;
     828    GameHandler *handler;   
    827829
    828830    if (!systemname.isEmpty() && !systemname.isNull())
    829831    {
    void GameHandler::Launchgame(RomInfo *romdata, QString systemname) 
    889891        }
    890892    }
    891893
    892     QString savedir = QDir::current().path();
    893     QDir d;
    894     if (!handler->SystemWorkingPath().isEmpty())
    895     {
    896         if (!d.cd(handler->SystemWorkingPath()))
    897         {
    898             VERBOSE(VB_GENERAL, LOC_ERR + QString("Failed to change to specified Working Directory: %1")
    899                     .arg(handler->SystemWorkingPath()));
    900         }
    901     }
    902     VERBOSE(VB_GENERAL, LOC + QString("Launching Game : %1 : %2")
    903            .arg(handler->SystemName())
    904            .arg(exec));
    905 
    906     GetMythUI()->AddCurrentLocation(QString("MythGame %1 ( %2 )").arg(handler->SystemName()).arg(exec));
     894    if (!game_launch_mutex)
     895        game_launch_mutex = new QMutex();
    907896
    908     QStringList cmdlist = exec.split(";");
    909     if (cmdlist.count() > 0)
    910     {
    911         for (QStringList::Iterator cmd = cmdlist.begin(); cmd != cmdlist.end();
    912              ++cmd )
    913         {
    914             VERBOSE(VB_GENERAL, LOC + QString("Executing : %1").arg(*cmd));
    915             myth_system(*cmd, kMSProcessEvents);
    916         }
    917     }
    918     else
     897    if (game_launch_mutex->tryLock())
    919898    {
    920         VERBOSE(VB_GENERAL, LOC + QString("Executing : %1").arg(exec));
    921         myth_system(exec, kMSProcessEvents);
     899        QString savedir = QDir::current().path();
     900        QDir d;
     901        if (!handler->SystemWorkingPath().isEmpty())
     902        {
     903            if (!d.cd(handler->SystemWorkingPath()))
     904            {
     905                VERBOSE(VB_GENERAL, LOC_ERR + QString("Failed to change to specified Working Directory: %1")
     906                        .arg(handler->SystemWorkingPath()));
     907            }
     908        }
     909        VERBOSE(VB_GENERAL, LOC + QString("Launching Game : %1 : %2")
     910                .arg(handler->SystemName())
     911                .arg(exec));
     912       
     913        GetMythUI()->AddCurrentLocation(QString("game %1 %2").arg(romdata->Gamename()).arg(handler->SystemName()));
     914       
     915        QStringList cmdlist = exec.split(";");
     916        if (cmdlist.count() > 0)
     917        {
     918            for (QStringList::Iterator cmd = cmdlist.begin(); cmd != cmdlist.end();
     919                 ++cmd )
     920            {
     921                VERBOSE(VB_GENERAL, LOC + QString("Executing : %1").arg(*cmd));
     922                myth_system(*cmd, kMSProcessEvents | kMSAbortOnJump);
     923            }
     924        }
     925        else
     926        {
     927            VERBOSE(VB_GENERAL, LOC + QString("Executing : %1").arg(exec));
     928            myth_system(exec, kMSProcessEvents | kMSAbortOnJump);
     929        }
     930       
     931        GetMythUI()->RemoveCurrentLocation();
     932
     933        (void)d.cd(savedir);
     934       
     935        game_launch_mutex->unlock();
    922936    }
    923 
    924     GetMythUI()->RemoveCurrentLocation();
    925 
    926     (void)d.cd(savedir);     
    927937}
    928938
    929939RomInfo *GameHandler::CreateRomInfo(RomInfo *parent)
  • new file mythplugins/mythgame/mythgame/gamelauncher.cpp

    diff --git a/mythplugins/mythgame/mythgame/gamelauncher.cpp b/mythplugins/mythgame/mythgame/gamelauncher.cpp
    new file mode 100644
    index 0000000..16cfd26
    - +  
     1#include "gamelauncher.h"
     2#include "rominfo.h"
     3#include "gamehandler.h"
     4
     5#include <QObject>
     6#include <QRegExp>
     7
     8#include <mythcontext.h>
     9#include <mythdbcon.h>
     10#include <mythdialogs.h>
     11#include <util.h>
     12#include <mythdb.h>
     13#include <mythuihelper.h>
     14
     15#define LOC_ERR QString("MythGame:GAMELAUNCHER Error: ")
     16#define LOC QString("MythGame:GAMELAUNCHER: ")
     17
     18MythGameLauncher::MythGameLauncher()
     19{
     20    gCoreContext->addListener(this);
     21}
     22
     23void MythGameLauncher::customEvent(QEvent *e)
     24{
     25    if( e->type() != MythEvent::MythEventMessage)
     26        return;
     27   
     28    MythEvent *me = dynamic_cast<MythEvent *>(e);
     29    QString message = me->Message();
     30    QStringList tokens = message.split(" ", QString::SkipEmptyParts);
     31
     32    if (message.left(15) == "NETWORK_CONTROL")
     33    {
     34        QRegExp qr = QRegExp("NETWORK_CONTROL GAME LAUNCH (\\S+)( (.+))?");
     35        if(message.contains(qr))
     36        {           
     37            this->LaunchGame(qr.capturedTexts()[1], qr.capturedTexts()[3]);
     38            return;
     39        }
     40    }
     41}
     42
     43void MythGameLauncher::LaunchGame(QString name, QString system="")
     44{
     45    RomInfo info = RomInfo();
     46    info.setGamename(name);
     47    info.fillData();
     48
     49    VERBOSE(VB_GENERAL, LOC + QString("Rom Info %1 for game system %2").arg(info.Romname()).arg(info.Gamename()));
     50    GameHandler::count();
     51    GameHandler::Launchgame(&info,system);
     52}
  • new file mythplugins/mythgame/mythgame/gamelauncher.h

    diff --git a/mythplugins/mythgame/mythgame/gamelauncher.h b/mythplugins/mythgame/mythgame/gamelauncher.h
    new file mode 100644
    index 0000000..6fbc088
    - +  
     1// -*- Mode: c++ -*-
     2#ifndef GAMELAUNCHER_H_
     3#define GAMELAUNCHER_H_
     4
     5#include <QObject>
     6
     7class MythGameLauncher : public QObject
     8{
     9    Q_OBJECT
     10
     11  public:
     12    MythGameLauncher();
     13
     14    void LaunchGame(QString name, QString type);
     15
     16    void customEvent(QEvent *event);
     17};
     18   
     19#endif /* GAMELAUNCHER_H_ */
  • mythplugins/mythgame/mythgame/main.cpp

    diff --git a/mythplugins/mythgame/mythgame/main.cpp b/mythplugins/mythgame/mythgame/main.cpp
    index 9345a8c..bbb5f05 100644
    a b using namespace std; 
    1111#include "rominfo.h"
    1212#include "gamesettings.h"
    1313#include "dbcheck.h"
     14#include "gamelauncher.h"
    1415
    1516#include <mythcontext.h>
    1617#include <mythdbcon.h>
    using namespace std; 
    2425#define LOC_ERR QString("MythGame:MAIN Error: ")
    2526#define LOC QString("MythGame:MAIN: ")
    2627
     28MythGameLauncher *launcher;
     29
    2730struct GameData
    2831{
    2932};
    int mythplugin_init(const char *libversion) 
    146149//    settings.Load();
    147150//    settings.Save();
    148151
     152    launcher = new MythGameLauncher();
     153
    149154    setupKeys();
    150155
    151156    return 0;
    152157}
    153158
     159void mythplugin_destroy(void)
     160{
     161    delete launcher;
     162}
     163
    154164int mythplugin_run(void)
    155165{
    156166    return RunGames();
  • mythplugins/mythgame/mythgame/mythgame.pro

    diff --git a/mythplugins/mythgame/mythgame/mythgame.pro b/mythplugins/mythgame/mythgame/mythgame.pro
    index 2b934a6..a99dc3f 100644
    a b INSTALLS += target installscripts installgiantbomb installgiantbombxsl 
    2020
    2121# Input
    2222HEADERS += gamehandler.h rominfo.h unzip.h gamesettings.h gameui.h
    23 HEADERS += rom_metadata.h romedit.h gamedetails.h
     23HEADERS += rom_metadata.h romedit.h gamedetails.h gamelauncher.h
    2424
    2525SOURCES += main.cpp gamehandler.cpp rominfo.cpp gameui.cpp unzip.c
    2626SOURCES += gamesettings.cpp dbcheck.cpp rom_metadata.cpp romedit.cpp
    27 SOURCES += gamedetails.cpp
     27SOURCES += gamedetails.cpp gamelauncher.cpp
    2828
    2929use_hidesyms {
    3030    QMAKE_CXXFLAGS += -fvisibility=hidden
  • mythtv/libs/libmythdb/mythsystem.cpp

    diff --git a/mythtv/libs/libmythdb/mythsystem.cpp b/mythtv/libs/libmythdb/mythsystem.cpp
    index 176901c..935a454 100644
    a b typedef struct { 
    4848    uint    result;
    4949    time_t  timeout;
    5050    bool    background;
     51    bool    abortOnJump;
    5152} PidData_t;
    5253
    5354typedef QMap<pid_t, PidData_t *> PidMap_t;
    5455
    5556class MythSystemReaper : public QThread
    5657{
    57     public:
    58         void run(void);
    59         uint waitPid( pid_t pid, time_t timeout, bool background = false,
    60                       bool processEvents = true );
    61         uint abortPid( pid_t pid );
    62     private:
    63         PidMap_t    m_pidMap;
    64         QMutex      m_mapLock;
     58  public:
     59    void run(void);
     60    uint waitPid( pid_t pid, time_t timeout, bool background = false,
     61                  bool processEvents = true, bool abortOnJump = false );
     62    uint abortPid( pid_t pid );
     63    uint abortOnJump(void);
     64
     65  private:
     66    PidMap_t    m_pidMap;
     67    QMutex      m_mapLock;
    6568};
    6669
    6770static class MythSystemReaper *reaper = NULL;
    void MythSystemReaper::run(void) 
    103106            pidData->result = GENERIC_EXIT_TIMEOUT;
    104107            VERBOSE(VB_GENERAL, QString("Child PID %1 timed out, killing")
    105108                .arg(pid));
    106             kill(pid, SIGTERM);
     109            kill(-pid, SIGTERM);
    107110            usleep(500);
    108             kill(pid, SIGKILL);
     111            kill(-pid, SIGKILL);
    109112            pidData->mutex.unlock();
    110113        }
    111114        count = m_pidMap.size();
    void MythSystemReaper::run(void) 
    167170}
    168171
    169172uint MythSystemReaper::waitPid( pid_t pid, time_t timeout, bool background,
    170                                 bool processEvents )
     173                                bool processEvents, bool abortOnJump )
    171174{
    172175    PidData_t  *pidData = new PidData_t;
    173176    uint        result;
    uint MythSystemReaper::waitPid( pid_t pid, time_t timeout, bool background, 
    178181        pidData->timeout = 0;
    179182
    180183    pidData->background = background;
     184    pidData->abortOnJump = abortOnJump;
    181185
    182186    pidData->mutex.lock();
    183187    m_mapLock.lock();
    uint MythSystemReaper::abortPid( pid_t pid ) 
    222226    delete pidData;
    223227
    224228    VERBOSE(VB_GENERAL, QString("Child PID %1 aborted, killing") .arg(pid));
    225     kill(pid, SIGTERM);
     229    kill(-pid, SIGTERM);
    226230    usleep(500);
    227     kill(pid, SIGKILL);
     231    kill(-pid, SIGKILL);
    228232    result = GENERIC_EXIT_ABORTED;
    229233    return( result );
    230234}
     235
     236uint MythSystemReaper::abortOnJump( void )
     237{
     238    PidMap_t::iterator i,next;
     239    QList<pid_t>::iterator j;
     240    uint result = GENERIC_EXIT_ABORTED;
     241
     242    QList<pid_t> pids = QList<pid_t>();
     243
     244    m_mapLock.lock();
     245    for( i = m_pidMap.begin(); i != m_pidMap.end(); ++i )
     246    {
     247        if( (i.value()->abortOnJump) )
     248        {
     249            pids << i.key();
     250            VERBOSE(VB_GENERAL, QString("pid : %1 ( %2 ; %3 ; %4 )").arg(i.key()).arg(i.value()->result).arg(i.value()->timeout).arg(i.value()->background?"background":"foreground"));
     251        }
     252    }   
     253    m_mapLock.unlock();
     254
     255    for( j = pids.begin(); j != pids.end(); ++j )
     256    {
     257        VERBOSE(VB_GENERAL, QString("SIGTERM process %1").arg(*j));
     258        kill(-(*j), SIGTERM);
     259    }
     260
     261    usleep(500);
     262
     263    for( j = pids.begin(); j != pids.end(); ++j )
     264    {
     265        VERBOSE(VB_GENERAL, QString("SIGKILL process %1").arg(*j));
     266        kill(-(*j), SIGKILL);   
     267    }
     268
     269    return result;
     270}
    231271#endif
    232272
    233273
    uint myth_system(const QString &command, uint flags, uint timeout) 
    257297
    258298    if( result == GENERIC_EXIT_RUNNING )
    259299        result = myth_system_wait( pid, timeout, (flags & kMSRunBackground),
    260                                    (flags & kMSProcessEvents) );
     300                                   (flags & kMSProcessEvents),
     301                                   (flags & kMSAbortOnJump));
    261302#else
    262303    STARTUPINFO si;
    263304    PROCESS_INFORMATION pi;
    pid_t myth_system_fork(const QString &command, uint &result) 
    380421         * execl calls in the child.  It causes occasional locking issues that
    381422         * cause deadlocked child processes. */
    382423
     424        /* Set the process group id to be the same as the pid of this child process
     425         * This ensures that any subprocesses launched by this process can be killed
     426         * along with the process itself. */
     427        setpgid(0,0);
     428
    383429        /* Close all open file descriptors except stdout/stderr */
    384430        for (int i = sysconf(_SC_OPEN_MAX) - 1; i > 2; i--)
    385431            close(i);
    pid_t myth_system_fork(const QString &command, uint &result) 
    427473}
    428474
    429475uint myth_system_wait(pid_t pid, uint timeout, bool background,
    430                       bool processEvents)
     476                      bool processEvents, bool abortOnJump)
    431477{
    432478    if( reaper == NULL )
    433479    {
    uint myth_system_wait(pid_t pid, uint timeout, bool background, 
    436482    }
    437483    VERBOSE(VB_GENERAL, QString("PID %1: launched%2") .arg(pid)
    438484        .arg(background ? " in the background, not waiting" : ""));
    439     return reaper->waitPid(pid, timeout, background, processEvents);
     485    return reaper->waitPid(pid, timeout, background, processEvents, abortOnJump);
    440486}
    441487
    442488uint myth_system_abort(pid_t pid)
    uint myth_system_abort(pid_t pid) 
    449495    VERBOSE(VB_GENERAL, QString("PID %1: aborted") .arg(pid));
    450496    return reaper->abortPid(pid);
    451497}
     498
     499uint myth_system_abort_on_jump( void )
     500{
     501    if( reaper == NULL )
     502    {
     503        reaper = new MythSystemReaper;
     504        reaper->start();
     505    }
     506    VERBOSE(VB_GENERAL, QString("Aborting system blocking processes"));
     507    return reaper->abortOnJump();
     508}
    452509#endif
    453510
    454511
  • mythtv/libs/libmythdb/mythsystem.h

    diff --git a/mythtv/libs/libmythdb/mythsystem.h b/mythtv/libs/libmythdb/mythsystem.h
    index 54c9ffa..702c42c 100644
    a b typedef enum MythSystemMask { 
    1313    kMSRunBackground            = 0x00000004, //< run child in the background
    1414    kMSProcessEvents            = 0x00000008, //< process events while waiting
    1515    kMSInUi                     = 0x00000010, //< the parent is in the UI
     16    kMSAbortOnJump              = 0x00000020, //< abort this process when a jump-point is activated
    1617} MythSystemFlag;
    1718
    1819MPUBLIC unsigned int myth_system(const QString &command,
    MPUBLIC void myth_system_post_flags(uint &flags); 
    2425#ifndef USING_MINGW
    2526MPUBLIC pid_t myth_system_fork(const QString &command, uint &result);
    2627MPUBLIC uint myth_system_wait(pid_t pid, uint timeout, bool background = false,
    27                               bool processEvents = true);
     28                              bool processEvents = true, bool abortOnJump = false);
    2829MPUBLIC uint myth_system_abort(pid_t pid);
     30MPUBLIC uint myth_system_abort_on_jump( void );
    2931#endif
    3032
    3133#endif
  • mythtv/libs/libmythui/mythmainwindow.cpp

    diff --git a/mythtv/libs/libmythui/mythmainwindow.cpp b/mythtv/libs/libmythui/mythmainwindow.cpp
    index 08c5851..560b0a4 100644
    a b using namespace std; 
    4444#include "compat.h"
    4545#include "mythsignalingtimer.h"
    4646#include "mythcorecontext.h"
     47#include "mythsystem.h"
    4748
    4849// Libmythui headers
    4950#include "myththemebase.h"
    void MythMainWindow::JumpTo(const QString& destination, bool pop) 
    16571658        screenShot();
    16581659    else if (d->destinationMap.count(destination) > 0 && d->exitmenucallback == NULL)
    16591660    {
     1661#ifndef USING_MINGW
     1662        myth_system_abort_on_jump();
     1663#endif /* USING_MINGW */
     1664
    16601665        d->exitingtomain = true;
    16611666        d->popwindows = pop;
    16621667        d->exitmenucallback = d->destinationMap[destination].callback;
  • mythtv/programs/mythfrontend/networkcontrol.cpp

    diff --git a/mythtv/programs/mythfrontend/networkcontrol.cpp b/mythtv/programs/mythfrontend/networkcontrol.cpp
    index c091433..21cc70d 100644
    a b QString NetworkControl::processPlay(NetworkCommand *nc, int clientID) 
    651651                             "%1, cannot play requested file.")
    652652                             .arg(GetMythUI()->GetCurrentLocation());
    653653        }
     654    } else if ((nc->getArgCount() >= 3) &&
     655               (is_abbrev("game", nc->getArg(1))))             
     656    {
     657        message = QString("NETWORK_CONTROL GAME LAUNCH %1 %2").arg(nc->getArg(2)).arg(nc->getFrom(3));
     658        result = QString("OK");
    654659    }
    655660    // Everything below here requires us to be in playback mode so check to
    656661    // see if we are