Ticket #9090: mythgame-remote-launch.patch

File mythgame-remote-launch.patch, 15.2 KB (added by James P. Barrett <james.barrett@…>, 3 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