1
/***************************************************************************
2
 * copyright            : (C) 2007 Shane King <kde@dontletsstart.com>      *
3
 **************************************************************************/
4
5
/***************************************************************************
6
 *                                                                         *
7
 *   This program is free software; you can redistribute it and/or modify  *
8
 *   it under the terms of the GNU General Public License as published by  *
9
 *   the Free Software Foundation; either version 2 of the License, or     *
10
 *   (at your option) any later version.                                   *
11
 *                                                                         *
12
 ***************************************************************************/
13
14
#include "AmarokProcess.h"    
15
#include "Debug.h"
16
17
#include <QTextCodec>
18
19
#include <fcntl.h>
20
#include <sys/time.h>
21
#include <sys/resource.h>
22
#include <unistd.h>
23
24
AmarokProcess::AmarokProcess(QObject *parent) 
25
    : KProcess(parent), lowPriority(false) 
26
{
27
    connect( this, SIGNAL( finished( int ) ), this, SLOT( finished() ) );
28
    connect( this, SIGNAL( readyReadStandardOutput() ), this, SLOT( readyReadStandardOutput() ) );
29
    connect( this, SIGNAL( readyReadStandardError() ), this, SLOT( readyReadStandardError() ) );
30
}
31
32
/** 
33
 * Due to xine-lib, we have to make KProcess close all fds, otherwise we get "device is busy" messages
34
 * exploiting setupChildProcess(), a virtual method that
35
 * happens to be called in the forked process
36
 * See bug #103750 for more information.
37
 */
38
void
39
AmarokProcess::setupChildProcess()
40
{
41
    KProcess::setupChildProcess();
42
43
#ifdef Q_OS_UNIX
44
    // can't get at the fds that QProcess needs to keep around to do its status
45
    // tracking , but fortunately it sets them to close on exec anyway, so if
46
    // we do likewise to everything then we should be ok.
47
    for(int i = sysconf(_SC_OPEN_MAX) - 1; i > 2; i--)
48
        fcntl(i, F_SETFD, FD_CLOEXEC);
49
50
    if( lowPriority )
51
        setpriority( PRIO_PROCESS, 0, 19 );
52
#endif
53
}
54
55
void
56
AmarokProcess::start()
57
{
58
    KProcess::start();
59
60
#ifdef Q_OS_WIN32
61
    if( lowPriority )
62
        SetPriorityClass( QProcess::pid()->hProcess, IDLE_PRIORITY_CLASS );
63
#endif
64
}
65
66
void
67
AmarokProcess::finished() // SLOT
68
{
69
    emit processExited( this );
70
}
71
72
void
73
AmarokProcess::readyReadStandardOutput() // SLOT
74
{
75
    emit receivedStdout( this );
76
}
77
78
void
79
AmarokProcess::readyReadStandardError() // SLOT
80
{
81
    emit receivedStderr( this );
82
}
83
84
// AmarokProcIO
85
AmarokProcIO::AmarokProcIO ( QObject *parent )
86
    : AmarokProcess( parent ), codec( QTextCodec::codecForName( "UTF-8" ) )
87
{
88
}
89
90
bool 
91
AmarokProcIO::writeStdin (const QString &line)
92
{
93
    return write( codec->fromUnicode( line + '\n' ) ) > 0;
94
}
95
96
int 
97
AmarokProcIO::readln (QString &line)
98
{
99
    QByteArray bytes = readLine();
100
    if (bytes.length() == 0)
101
    {
102
        return -1;
103
    }
104
    else
105
    {
106
        // convert and remove \n
107
        line = codec->toUnicode( bytes.data(), bytes.length() - 1);
108
        return line.length();
109
    }
110
}
111
112
void
113
AmarokProcIO::start()
114
{
115
    connect (this, SIGNAL (readyReadStandardOutput()), this, SLOT (readyReadStandardOutput()));
116
117
    KProcess::start ();
118
}
119
120
void 
121
AmarokProcIO::readyReadStandardOutput()
122
{
123
    if( canReadLine() )
124
        emit readReady( this );
125
}
126
127
// AmarokShellProcess
128
AmarokShellProcess &
129
AmarokShellProcess::operator<<(const QString& arg)
130
{
131
    if( program().isEmpty() )
132
        setShellCommand( arg );
133
    else
134
        AmarokProcess::operator<<( arg );
135
    return *this;
136
}
137
138
AmarokShellProcess &
139
AmarokShellProcess::operator<<(const QStringList& args)
140
{
141
    foreach( const QString &arg, args )
142
        *this << arg;
143
    return *this;
144
}