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