You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
401 lines
11 KiB
401 lines
11 KiB
/*************************************************************************** |
|
* Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
***************************************************************************/ |
|
|
|
#include <math.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <string.h> |
|
#include <sys/ipc.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
#include <unistd.h> |
|
|
|
#include <qfile.h> |
|
|
|
#include <qapplication.h> |
|
#include <kdebug.h> |
|
#include <klocale.h> |
|
#include <kmessagebox.h> |
|
#include <kprocess.h> |
|
#include <ktempfile.h> |
|
|
|
|
|
#include "conf/settings.h" |
|
#include "interpreter_cmd.h" |
|
|
|
ProcessData :: ProcessData () |
|
{ |
|
KTempFile* tmp[2]; |
|
tmp[0] = new KTempFile(); |
|
tmp[1] = new KTempFile(); |
|
tmp[0]->close(); |
|
tmp[1]->close(); |
|
names[0]=QFile::encodeName( tmp[0]->name() ); |
|
names[1]=QFile::encodeName( tmp[1]->name() ); |
|
tmp[0]->unlink(); |
|
tmp[1]->unlink(); |
|
delete tmp[0]; |
|
delete tmp[1]; |
|
|
|
mkfifo( names[0] , S_IRUSR | S_IWUSR ); |
|
mkfifo( names[1] , S_IRUSR | S_IWUSR ); |
|
fds[0]=open ( names[0], O_RDWR ); |
|
fds[1]=open ( names[1], O_RDWR ); |
|
} |
|
|
|
ProcessData :: ~ProcessData() |
|
{ |
|
close (fds[0]); |
|
close (fds[1]); |
|
QFile::remove ( names[0] ); |
|
QFile::remove ( names[1] ); |
|
} |
|
|
|
QPixmap* GSInterpreterCMD::takePixmap() |
|
{ |
|
kdDebug(4655) << "taking pixmap" << endl; |
|
QPixmap * x=m_pixmap; |
|
m_pixmap=0; |
|
return x; |
|
} |
|
|
|
|
|
GSInterpreterCMD::GSInterpreterCMD( const QString & fileName ) : |
|
m_process ( 0 ), |
|
m_structurePending( false ), |
|
m_magnify ( 1 ), |
|
m_orientation ( CDSC_PORTRAIT ), |
|
m_name ( fileName ), |
|
m_aaGfx (1), |
|
m_aaText (1), |
|
m_pfonts (false) |
|
{ |
|
kdDebug(4655) << "Constructing async interpreter!" << endl; |
|
m_pixmap=0; |
|
} |
|
|
|
GSInterpreterCMD::~GSInterpreterCMD() |
|
{ |
|
if (!m_pixmap) |
|
delete m_pixmap; |
|
if ( running() ) |
|
stop(false); |
|
// remove (crashes kpdf somehow, probably because |
|
// the destuction thread does the same a line higher |
|
/* this should not be needed! |
|
if (m_stoppingPids.count() > 0) |
|
{ |
|
QMapIterator<pid_t,ProcessData*> it, end=m_stoppingPids.end(); |
|
while ( it != end ) |
|
{ |
|
ProcessData *p=it.data(); |
|
++it; |
|
delete p; |
|
} |
|
}*/ |
|
m_stoppingPids.clear(); |
|
unlock(); |
|
} |
|
|
|
void GSInterpreterCMD::destroyInternalProcess(KProcess * stop) |
|
{ |
|
pid_t pId=stop->pid(); |
|
kdDebug(4655) << "Destroy thread pid " << getpid() << " of " << pId << endl; |
|
int x=1; |
|
ProcessData *mem=m_stoppingPids[pId]; |
|
write(mem->fds[0],&x,sizeof(int)); |
|
stop->wait(); |
|
kdDebug(4655) << "Normal exit : " << !stop->isRunning() << endl; |
|
// give it the time to close the interpreter before we kill it |
|
if( stop->isRunning() ) |
|
{ |
|
stop->kill(); |
|
stop->wait(5); |
|
kdDebug(4655) << "after stopping, the proces running: " |
|
<< stop->isRunning() << endl; |
|
if( stop->isRunning() ) |
|
stop->kill( SIGKILL ); |
|
} |
|
m_stoppingPids.remove( pId ); |
|
delete stop; |
|
delete mem; |
|
} |
|
|
|
bool GSInterpreterCMD::running () |
|
{ |
|
if (m_process==0) |
|
{ |
|
kdDebug (4655) << "no process\n"; |
|
return false; |
|
} |
|
else |
|
{ |
|
kdDebug(4655) << "running " << m_process->isRunning() << endl; |
|
return m_process->isRunning(); |
|
} |
|
} |
|
|
|
void GSInterpreterCMD::setStructure(GSInterpreterLib::Position prolog, GSInterpreterLib::Position setup) |
|
{ |
|
kdDebug(4655) << "setStructure()" << endl; |
|
m_structurePending=true; |
|
m_data[0]=prolog; |
|
m_data[1]=setup; |
|
} |
|
|
|
bool GSInterpreterCMD::stop(bool async) |
|
{ |
|
kdDebug(4655) << "stop()" << endl; |
|
// if( !_interpreterBusy ) return; |
|
|
|
if ( running() ) |
|
{ |
|
if (m_stoppingPids.contains(m_process->pid())) |
|
return true; |
|
KProcess * stop=m_process; |
|
m_stoppingPids.insert ( stop->pid(), m_processData ); |
|
m_process=0; |
|
kdDebug(4655) << "Launching destroy thread" << endl; |
|
if (!async) |
|
destroyInternalProcess(stop); |
|
else |
|
{ |
|
switch ( fork() ) |
|
{ |
|
case -1: |
|
// we cant kill it in a fork, kill it outside a fork |
|
destroyInternalProcess(stop); |
|
break; |
|
case 0: |
|
destroyInternalProcess(stop); |
|
_exit(0); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
bool GSInterpreterCMD::start() |
|
{ |
|
kdDebug(4655) << "start()" << endl; |
|
if ( m_process && m_process->isRunning() ) |
|
{ |
|
kdDebug(4655) << "ERROR: starting an interpreter while one is running" << endl; |
|
return false; |
|
} |
|
|
|
m_processData=new ProcessData(); |
|
m_process = new KProcess; |
|
|
|
(*m_process) << QString("kpdflibgsasyncgenerator"); |
|
// Order of sending: fileName, msgQueueId, media type, magnify, orientation, expected width, height |
|
QStringList list; |
|
list << m_name |
|
<< m_processData->names[0] |
|
<< m_processData->names[1] |
|
<< m_media.lower() |
|
<< QString::number ( m_magnify ) |
|
<< QString::number ( m_orientation ) |
|
<< QString::number ( m_width ) |
|
<< QString::number ( m_height ) |
|
<< QString::number ( m_pfonts ? 1 : 0 ) |
|
<< QString::number (m_aaText) |
|
<< QString::number (m_aaGfx); |
|
|
|
kdDebug(4655) << "Argument count: " << list.count() << endl; |
|
(*m_process) << list; |
|
/*connect( m_process, SIGNAL( processExited( KProcess* ) ), |
|
this, SLOT( slotProcessExited( KProcess* ) ) ); |
|
connect( m_process, SIGNAL( receivedStdout( KProcess*, char*, int ) ), |
|
this, SLOT( output( KProcess*, char*, int ) ) ); |
|
connect( m_process, SIGNAL( receivedStderr( KProcess*, char*, int ) ), |
|
this, SLOT( output( KProcess*, char*, int ) ) ); |
|
connect( m_process, SIGNAL( wroteStdin( KProcess*) ), |
|
this, SLOT( gs_input( KProcess* ) ) );*/ |
|
|
|
// Finally fire up the interpreter. |
|
// kdDebug(4500) << "KPSWidget: starting interpreter" << endl; |
|
|
|
if( m_process->start( KProcess::NotifyOnExit, |
|
/*m_usePipe ?*/ KProcess::All /*: KProcess::AllOutput*/ ) ) |
|
{ |
|
kdDebug(4655) << "Starting async! " << m_process->pid() << endl; |
|
return true; |
|
} |
|
else |
|
{ |
|
emit error(i18n( "Could not start kpdf's libgs helper application. This is most likely " |
|
"caused by kpdflibgsasyncgenerator not being installed, or installed to a " |
|
"directory not listed in the environment PATH variable."),0); |
|
kdDebug(4655) << "Could not start helper" << endl; |
|
return false; |
|
} |
|
} |
|
|
|
void GSInterpreterCMD::setOrientation( int orientation ) |
|
{ |
|
lock(); |
|
if( m_orientation != orientation ) |
|
{ |
|
m_orientation = orientation; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
void GSInterpreterCMD::setMagnify( double magnify ) |
|
{ |
|
lock(); |
|
if( m_magnify != magnify ) |
|
{ |
|
m_magnify = magnify; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
void GSInterpreterCMD::setMedia( QString media ) |
|
{ |
|
lock(); |
|
if( m_media != media ) |
|
{ |
|
m_media = media; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
void GSInterpreterCMD::setPlatformFonts(bool pfonts) |
|
{ |
|
lock(); |
|
if( m_pfonts != pfonts ) |
|
{ |
|
m_pfonts = pfonts; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
|
|
void GSInterpreterCMD::setSize( int w, int h ) |
|
{ |
|
lock(); |
|
if ( m_width != w ) |
|
{ |
|
m_width=w; |
|
stop(); |
|
|
|
} |
|
if ( m_height != h ) |
|
{ |
|
m_height=h; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
void GSInterpreterCMD::setAABits(int text, int graphics) |
|
{ |
|
lock(); |
|
if ( m_aaText!= text ) |
|
{ |
|
m_aaText=text; |
|
stop(); |
|
|
|
} |
|
if ( m_aaGfx != graphics ) |
|
{ |
|
m_aaGfx=graphics; |
|
stop(); |
|
} |
|
unlock(); |
|
} |
|
|
|
bool GSInterpreterCMD::run( GSInterpreterLib::Position pos) |
|
{ |
|
kdDebug(4655) << "Running request with size: " << m_width << "x" << m_height << endl; |
|
|
|
if( !running() ) |
|
return false; |
|
|
|
lock(); |
|
if ( m_pixmap != 0 ) |
|
{ |
|
kdDebug(4655) << "ERROR DELETING PIXMAP, THIS SHOULD NOT HAPPEN" << endl; |
|
delete m_pixmap; |
|
} |
|
// the pixmap to which the generated image will be copied |
|
m_pixmap = new QPixmap (m_width, m_height); |
|
|
|
m_info.pos=pos; |
|
m_info.sync=true; |
|
m_info.handle=m_pixmap->handle(); |
|
start(); |
|
return true; |
|
} |
|
|
|
void GSInterpreterCMD::run() |
|
{ |
|
// we are inside a thread |
|
kdDebug(4655)<< "Generation thread started " << getpid() << endl; |
|
int x; |
|
|
|
// pending structural information -> send them |
|
if (m_structurePending) |
|
{ |
|
kdDebug(4655) << "sending structural data" << endl; |
|
PageInfo pageInf; |
|
for (int i=0;i<2;i++) |
|
{ |
|
x=0; |
|
write ( m_processData->fds[0] , &x, sizeof(int) ); |
|
pageInf.sync=false; |
|
pageInf.pos=m_data[i]; |
|
pageInf.handle=m_info.handle; |
|
write( m_processData->fds[0], &pageInf, sizeof(pageInf)); |
|
read( m_processData->fds[1],&x,sizeof(int)); |
|
} |
|
m_structurePending=false; |
|
} |
|
kdDebug(4655)<< "sending page request" << endl; |
|
// Communication with the helper looks like this |
|
// 1. Sendign a 0 to helper telling it to start a function that processes the request |
|
x=0; |
|
write ( m_processData->fds[0] , &x, sizeof(int) ); |
|
// 2. sending the structure with relevant information |
|
write ( m_processData->fds[0], &m_info, sizeof(m_info) ); |
|
// 3. we will receive a '3' from the helper when request is done, |
|
// the helper will copy the pixmap using XCopyArea |
|
read ( m_processData->fds[1], &x, sizeof(int) ); |
|
unlock(); |
|
kdDebug(4655)<< "pximap ready" << endl; |
|
if (x==3) |
|
{ |
|
kdDebug(4655)<< "sending the pximap to generator" << endl; |
|
// inform interpreter about PixmaRequest being done |
|
QCustomEvent * readyEvent = new QCustomEvent( GS_DATAREADY_ID ); |
|
// set sth just to send nonempty |
|
readyEvent->setData(&x); |
|
QApplication::postEvent( this , readyEvent ); |
|
} |
|
} |
|
|
|
void GSInterpreterCMD::customEvent( QCustomEvent * e ) |
|
{ |
|
if (e->type() == GS_DATAREADY_ID ) |
|
{ |
|
kdDebug(4655) << "emitting signal" << endl; |
|
emit Finished(m_pixmap); |
|
} |
|
} |
|
|
|
#include "interpreter_cmd.moc"
|
|
|