Beispiel #1
0
/*
  Process Monitor thread, for monitoring processes running time
*/
void * processMonitor(void * skip) {
  int pid, status;
  struct timespec tm;
  while(1) {
    M_LOCK(&mutexRunningProcesses);
    while(runningProcesses==0) {
      if (exitCalled && processesWaitingToRun==0) {
        pthread_exit(NULL);
      }
      C_WAIT(&condRunningProcesses, &mutexRunningProcesses);
    }

    M_UNLOCK(&mutexRunningProcesses);

    pid = wait(&status);
	  if (pid < 0) {
  	  if (errno == EINTR) continue;
  	  else {
  	   	perror("Error waiting for child");
  	   	exit (EXIT_FAILURE);
  	  }
  	}
  	else {
      clock_gettime( CLOCK_MONOTONIC, &tm);
      M_LOCK(&mutexRunningProcesses);
      runningProcesses--;
      C_SIGNAL(&condFreeSlots);
      M_UNLOCK(&mutexRunningProcesses);
  	}
    endProcess(pid, status, tm);
  }
}
Beispiel #2
0
void ProcessSlaveActivity::main() 
{ 
#ifdef TIME_ACTIVITIES
    if (timeActivities)
        lastCycles = get_cycles_now();
#endif
    try { process(); }
    catch (IException *_e)
    {
        IThorException *e = QUERYINTERFACE(_e, IThorException);
        if (e)
        {
            if (!e->queryActivityId())
            {
                e->setGraphId(container.queryOwner().queryGraphId());
                e->setActivityKind(container.getKind());
                e->setActivityId(container.queryId());
            }
        }
        else
        {
            e = MakeActivityException(this, _e);
            if (QUERYINTERFACE(_e, ISEH_Exception))
            {
                IThorException *e2 = MakeThorFatal(e, TE_SEH, "FATAL: (SEH)");
                e->Release();
                e = e2;
            }
            _e->Release();
        }
        ActPrintLog(e, NULL);
        exception.setown(e);
    }
    catch (std::exception & es)
    {
        StringBuffer m("FATAL std::exception ");
        if(dynamic_cast<std::bad_alloc *>(&es))
            m.append("out of memory (std::bad_alloc)");
        else
            m.append("standard library exception (std::exception ").append(es.what()).append(")");
        m.appendf(" in %"ACTPF"d",container.queryId());
        ActPrintLogEx(&queryContainer(), thorlog_null, MCerror, "%s", m.str());
        exception.setown(MakeThorFatal(NULL, TE_UnknownException, "%s", m.str()));
    }
    catch (CATCHALL)
    {
        ActPrintLogEx(&queryContainer(), thorlog_null, MCerror, "Unknown exception thrown in process()");
        exception.setown(MakeThorFatal(NULL, TE_UnknownException, "FATAL: Unknown exception thrown by ProcessThread"));
    }
    try { endProcess(); }
    catch (IException *_e)
    {
        ActPrintLog(_e, "Exception calling activity endProcess");
        fireException(_e);
        exception.set(_e);
        _e->Release();
    }
}
void ConnectionClient::finishProcess()
{
    TIME_SCOPE_DURATION("ConnectionClient::finishProcess");

    processAliveTimer.stop();

    disconnectProcessFinished();
    endProcess();
    disconnectFromServer();
    terminateProcess();
    killProcess();

    process_.reset();

    serverProxy_.resetCounter();
}
void * executeProcess(void *vargp){
	/*-----------------------------------DESCRIÇÃO--------------------------------*
     *                                                                            *
     *  Função para a criação de uma thread, recebe uma struct definida no iní-   *
     *  cio do programa como parâmetro e a partir dela, é possível se executar    *
     *  com flexiblidade o pequeno algoritmo descrito.                            *
     *                                                                            *
     *  Essa função recebe como parâmetro uma struct que contém os dois únicos    *
     *  parâmetros necessários. O cabeçalho da memória e o endereço do processo   *
     *  que criou essa thread.                                                    *
     *                                                                            *
     *  Para simular a execução de um processo, na verdade, fazemos com que o     *
     *  processo aguarde um tempo randômico antes de ser finalizado. Esse tempo   *
     *  está entre 1 e MAX_PROCESS_TIME que é uma definição do sistema.           *
     *                                                                            *
     *  Após a espera desse tempo, o processo chama sua própria função de exclu-  *
     *  são e aguarda até que o acesso a lista seja liberado pela fechadura       *
     *  mutex_listModify. Então, encerra o processo e libera a fechadura.         *
     *                                                                            *
     *----------------------------------------------------------------------------*/
	execution_arg *exec_arg = (execution_arg *) vargp;	
	time_t t;
	_program_time processTime;
	srand((unsigned) time(&t));
	processTime = 1 + rand() % (MAX_PROCESS_TIME - 1);

	while(processTime--){
		pthread_mutex_lock(&mutex_play);
		while(!play)
			pthread_cond_wait(&cond_play, &mutex_play);
		pthread_mutex_unlock(&mutex_play);		
		sleep(1);
	}

	pthread_mutex_lock(&mutex_listModify);
	endProcess(exec_arg->selfCase, exec_arg->memory);
	pthread_mutex_unlock(&mutex_listModify);

	pthread_exit((void *)NULL);
}
void BatchProcessImagesDialog::processAborted(bool removeFlag)
{
    kDebug() << "BatchProcessImagesDialog::processAborted";

    BatchProcessImagesItem *item = static_cast<BatchProcessImagesItem*>(**m_listFile2Process_iterator);
    m_listFiles->scrollToItem(m_listFiles->currentItem());

    item->changeResult(i18n("Aborted."));
    item->changeError(i18n("process aborted by user"));

    if (removeFlag == true)
    { // Try to delete de destination !
        KUrl deleteImage = m_ui->m_destinationUrl->url();
        deleteImage.addPath(item->nameDest());

        if (KIO::NetAccess::exists(deleteImage, KIO::NetAccess::DestinationSide, kapp->activeWindow())
                == true)
            KIO::NetAccess::del(deleteImage, kapp->activeWindow());
    }

    endProcess();
}
Beispiel #6
0
Job* Parser::parseLine (void) {
	job = new Job();
	currState = PARSCMD;
	int i, length, curr;
	int rflag;
	
	// Limpa o buffer de entrada para evitar loop infinito
	strcpy(line, "\0");
	std::cin.clear();
	
	std::cin.getline (line, MAX_LENGTH);
	
	i = 0;
	while (i < length && line[i] == ' ')	i++;
	length = strlen(line+i);
	// Checa se a linha nao estava em branco
	if (length == 0) {
		job->addFlag (shooSH_NOP);
		return job;
	} else {
		while (line[--length] == ' '); // pega os espacos do fim
		length++;
		if (strcmp (line+i, "exit") == 0) { //builtin
			job->addFlag (shooSH_EXIT);
			return job;
		}
	}
	if ((line+i)[length-1] == '&')
		job->setCommand (std::string (line+i, length-1));
	else
		job->setCommand (std::string (line+i, length));
		
	while (currState != PARSSUCCESS && currState != PARSFAIL) {
		if (currState == PARSCMD) {
			newProcess();
			newWord();
			rflag = 0;
			// pega espacos
			while (i < length && line[i] == ' ')	i++;
			// esperava um comando, mas nao veio nada (usado para pipe)
			if (i == length) {
				currState = PARSFAIL;
			} else {
				// le ate encontrar um espaco
				while (i < length && line[i] != ' ')	cmdList[cmdListSize][currChar++] = line[i++];
				currState = PARSNEXT;
			}
			endWord();
		} else if (currState == PARSNEXT) {
			// le espaco
			while (i < length && line[i] == ' ')	i++;
	
			if (i == length) { //chegou ao fim da linha
				currState = PARSSUCCESS;
				endProcess();
			} else {
				// procura token
				switch (line[i]) {
					case '<':
						i++;
						currState = PARSRIN;
						break;
					case '>':
						i++;
						currState = PARSROUT;
						break;
					case '2': //pode ser argumento ou redirecionamento de erro
						i++;
						currState = PARSTWO;
						break;
					case '|':
						i++;
						job->addFlag (shooSH_PIPE);
						endProcess();
						currState = PARSCMD;
						break;
					case '&':
						i++;
						job->addFlag (shooSH_BG);
						endProcess();
						currState = PARSSUCCESS;
						break;
					default:
						currState = PARSPARAM;
				}
			}
		} else if (currState == PARSPARAM) {
			newWord();
			while (i < length && line[i] != ' ' && line[i] != '\"' && line[i] != '\'')	cmdList[cmdListSize][currChar++] = line[i++];
			if (line[i] == '\"') {
				i++;
				while (i < length && line[i] != '\"')	cmdList[cmdListSize][currChar++] = line[i++];
				if (i == length) {
					endWord();
					currState = PARSFAIL;
				} else {
					i++;
					endWord();
					currState = PARSNEXT;
				}
			} else if (line[i] == '\'') {
				i++;
				while (i < length && line[i] != '\'')	cmdList[cmdListSize][currChar++] = line[i++];
				if (i == length) {
					endWord();
					currState = PARSFAIL;
				} else {
					i++;
					endWord();
					currState = PARSNEXT;
				}
			} else {
				endWord();
				currState = PARSNEXT;
			}
		} else if (currState == PARSTWO) {
			if (line[i] == '>') {
				i++;
				endWord();
				currState = PARSRERR;
			} else {
				i--;
				currState = PARSPARAM;
			}
			endWord();
		} else if (currState == PARSRERR) {
			if (line[i] == '>') { // append
				i++;
				rflag = REDERRA;
			} else { // trunc
				rflag = REDERRT;
			}
			currState = PARSFILENAME;
		} else if (currState == PARSRIN) {
			rflag = REDIN;
			currState = PARSFILENAME;
		} else if (currState == PARSROUT) {
			if (line[i] == '>') { // append
				i++;
				rflag = REDOUTA;
			} else { // trunc
				rflag = REDOUTT;
			}
			currState = PARSFILENAME;
		} else if (currState == PARSFILENAME) {
			while (i < length && line[i] == ' ')	i++;
			if (i == length)	currState = PARSFAIL;
			else {
				curr = 0;
				if (line[i] == '"') { // le nomes como "file name"
					i++;
					while (i < length && line[i] != '"')	filename[curr++] = line[i++];
					if (i == length)	currState = PARSFAIL;
					else	i++;
				} else if (line[i] == '\'') { // le nomes do tipo 'file name'
					i++;
					while (i < length && line[i] != '\'')	filename[curr++] = line[i++];
					if (i == length)	currState = PARSFAIL;
					else	i++;
				} else { // le nomes do tipo filename
					while (i < length && line[i] != ' ')	filename[curr++] = line[i++];
				}
				filename[curr] = '\0';
				job->setProcessFile (filename, rflag);
				currState = PARSNEXT;
			}
		}
	}
	if (currState == PARSFAIL)	job->addFlag (shooSH_FAIL);
	return job;
}
Beispiel #7
0
void ServerControl::start()
{
	try
	{
		TRACE("start() called\r\n");
		if (busy)
			throw "Server is already being monitored";
		busy = true;
		updateStatus(STATUS_UNKNOWN,STATUS_START);
		createProcess();
		updateStatus(STATUS_UP,STATUS_OK);
		
		int counter = 1;
		while (*go)
		{
			Sleep(time_pause); // wait 3 seconds
			try
			{
				if (!pingOnce())
				{
					counter+=2; // always add 2 then subtract 1 at end of loop
					updateStatus(STATUS_UNKNOWN,STATUS_NO_REPLY);
				}
			}
			catch (char*) // on errors in the pingonce, something bad happened so we let the process respawn immediately
			{
				updateStatus(STATUS_DOWN,STATUS_NO_REPLY);
				counter = 11;
			}
			
			if (counter > 10) // server has been gone for too long, or error
			{
				updateStatus(STATUS_DOWN,STATUS_STOP);
				endProcess();
				
				updateStatus(STATUS_UNKNOWN,STATUS_START);
				counter = 0;
				createProcess();
				updateStatus(STATUS_UP,STATUS_OK);
			}
			if (counter > 0) // subtract one to lower the number back to 0 when server is up (mapchanges etc)
			{
				if (counter == 1)
					updateStatus(STATUS_UP,STATUS_OK);
				counter--;
			}
		}
		
		if (!no_kill) // turned on if servers should remain active after program end
		{
			updateStatus(STATUS_UNKNOWN,STATUS_STOP);
			endProcess();
			updateStatus(STATUS_DOWN,STATUS_STOPPED);
		}
		
		busy = false;
		TRACE("start() stopped");
	}
	catch (...)
	{
		busy = false; // whatever happens, we're not busy anymore!
		throw;
	}
}
Beispiel #8
0
void SmbView::slotProcessExited(KProcess *)
{
    endProcess();
}
Beispiel #9
0
Anchor::~Anchor() {
  // Important: FIRST end the child process
  // THEN stop the event loop.
  endProcess();
  Process::stop();
}
void BatchProcessImagesDialog::slotFinished()
{
    if (m_convertStatus == PROCESS_DONE)
    {
        // processAborted() has already been called. No need to show the warning.
        return;
    }

    BatchProcessImagesItem *item = static_cast<BatchProcessImagesItem*>(**m_listFile2Process_iterator);
    m_listFiles->scrollToItem(m_listFiles->currentItem());

    if (m_ProcessusProc->exitStatus() == QProcess::CrashExit)
    {
        int code = KMessageBox::warningContinueCancel(this,
                   i18n("The 'convert' program from 'ImageMagick' package has been stopped abnormally"),
                   i18n("Error running 'convert'"));

        if (code == KMessageBox::Cancel)
        {
            processAborted(true);
        }
        else
        {
            item->changeResult(i18nc("batch process result", "Failed."));
            item->changeError(i18n("'convert' program from 'ImageMagick' package "
                                   "has been stopped abnormally."));
            ++*m_listFile2Process_iterator;
            ++m_progressStatus;
            m_ui->m_progress->setValue((int)((float) m_progressStatus * (float) 100 / (float) m_nbItem));

            if (**m_listFile2Process_iterator)
                startProcess();
            else
                endProcess();
        }
        return;
    }

    int ValRet = m_ProcessusProc->exitCode();
    kWarning() << "Convert exit (" << ValRet << ")";

    switch (ValRet)
    {
        case 0:
        { // Process finished successfully !
            item->changeResult(i18n("OK"));
            item->changeError(i18n("no processing error"));
            processDone();

            KUrl src;
            src.setPath(item->pathSrc());
            KUrl dest = m_ui->m_destinationUrl->url();
            dest.addPath(item->nameDest());
            QString errmsg;

            KUrl::List urlList;
            urlList.append(src);
            urlList.append(dest);
            iface()->refreshImages(urlList);

            if (!item->overWrote())
            {
                // Do not add an entry if there was an image at the location already.
                bool ok = iface()->addImage(dest, errmsg);

                if (!ok)
                {
                    int code = KMessageBox::warningContinueCancel(this, i18n(
                                  "<qt>Error adding image to application; error message was: "
                                  "<b>%1</b></qt>", errmsg),
                              i18n("Error Adding Image to Application"));

                    if (code == KMessageBox::Cancel)
                    {
                        slotProcessStop();
                        break;
                    }
                    else
                    {
                        item->changeResult(i18nc("batch process result", "Failed."));
                    }
                }
            }

            if (src != dest)
            {
                // Clone data in KIPI host application.
                KPImageInfo info(src);
                info.cloneData(dest);

                // Move XMP sidecar file.
                KPMetadata::moveSidecar(src, dest);
            }

            if (m_ui->m_removeOriginal->isChecked() && src != dest)
            {
                KUrl deleteImage(item->pathSrc());

                if (KIO::NetAccess::del(deleteImage, kapp->activeWindow()) == false)
                {
                    item->changeResult(i18nc("batch process result", "Warning:"));
                    item->changeError(i18n("cannot remove original image file."));
                }
                else
                {
                    iface()->delImage(item->pathSrc());
                }
            }
            break;
        }
        case 15:
        { //  process aborted !
            processAborted(true);
            break;
        }
        default :
        { // Processing error !
            item->changeResult(i18nc("batch process result", "Failed."));
            item->changeError(i18n("cannot process original image file."));
            break;
        }
    }

    ++*m_listFile2Process_iterator;
    ++m_progressStatus;
    m_ui->m_progress->setValue((int)((float)m_progressStatus *(float)100 / (float)m_nbItem));

    if (**m_listFile2Process_iterator)
        startProcess();
    else
        endProcess();
}
bool BatchProcessImagesDialog::startProcess()
{
    if (m_convertStatus == STOP_PROCESS)
    {
        endProcess();
        return true;
    }

    QString targetAlbum = m_ui->m_destinationUrl->url().path();

    //TODO check if it is valid also for remote URL's
    // this is a workarond for bug 117397
    QFileInfo dirInfo(targetAlbum + '/');
    if (!dirInfo.isDir() || !dirInfo.isWritable())
    {
        KMessageBox::error(this, i18n("You must specify a writable path for your output file."));
        endProcess();
        return true;
    }

    BatchProcessImagesItem* item = static_cast<BatchProcessImagesItem*>(**m_listFile2Process_iterator);
    m_listFiles->setCurrentItem(item);

    // Lock current item into KIPI host application
    KPFileReadLocker(iface(), item->pathSrc());

    if (prepareStartProcess(item, targetAlbum) == false)   // If there is a problem during the
    {                                                   // preparation -> pass to the next item!
        ++*m_listFile2Process_iterator;
        ++m_progressStatus;
        m_ui->m_progress->setValue((int)((float)m_progressStatus *(float)100 / (float)m_nbItem));
        item = static_cast<BatchProcessImagesItem*>(**m_listFile2Process_iterator);
        m_listFiles->setCurrentItem(item);

        if (**m_listFile2Process_iterator)
        {
            startProcess();
            return true;
        }
        else
        {
            endProcess();
            return true;
        }
    }

    KUrl desturl(targetAlbum + '/' + item->nameDest());

    if (KIO::NetAccess::exists(desturl, KIO::NetAccess::DestinationSide,
                               kapp->activeWindow()) == true)
    {
        switch (overwriteMode())
        {
            case OVERWRITE_ASK:
            {
                int ValRet = KMessageBox::warningYesNoCancel(this,
                            i18n("The destination file \"%1\" already exists;\n"
                                  "do you want overwrite it?", item->nameDest()),
                            i18n("Overwrite Destination Image File"), KStandardGuiItem::cont());

                if (ValRet == KMessageBox::No)
                {
                    item->changeResult(i18n("Skipped."));
                    item->changeError(i18n("destination image file already exists (skipped by user)."));
                    ++*m_listFile2Process_iterator;
                    ++m_progressStatus;
                    m_ui->m_progress->setValue((int)((float)m_progressStatus *(float)100 / (float)m_nbItem));

                    if (**m_listFile2Process_iterator)
                    {
                        startProcess();
                        return true;
                    }
                    else
                    {
                        endProcess();
                        return true;
                    }
                }
                else if (ValRet == KMessageBox::Cancel)
                {
                    processAborted(false);
                    return false;
                }
                else
                {
                    item->setDidOverWrite(true);
                }

                break;
            }

            case OVERWRITE_RENAME:
            {
                QFileInfo Target(targetAlbum + '/' + item->nameDest());
                QString newFileName = RenameTargetImageFile(&Target);

                if (newFileName.isNull())
                {
                    item->changeResult(i18nc("batch process result", "Failed."));
                    item->changeError(i18n("destination image file already exists and cannot be renamed."));
                    ++*m_listFile2Process_iterator;
                    ++m_progressStatus;
                    m_ui->m_progress->setValue((int)((float)m_progressStatus *(float)100 / (float)m_nbItem));

                    if (**m_listFile2Process_iterator)
                    {
                        startProcess();
                        return true;
                    }
                    else
                    {
                        endProcess();
                        return true;
                    }
                }
                else
                {
                    QFileInfo newTarget(newFileName);
                    item->changeNameDest(newTarget.fileName());
                }

                break;
            }

            case OVERWRITE_SKIP:
            {
                item->changeResult(i18n("Skipped."));
                item->changeError(i18n("destination image file already exists (skipped automatically)."));
                ++*m_listFile2Process_iterator;
                ++m_progressStatus;
                m_ui->m_progress->setValue((int)((float)m_progressStatus *(float)100 / (float)m_nbItem));

                if (**m_listFile2Process_iterator)
                {
                    startProcess();
                    return true;
                }
                else
                {
                    endProcess();
                    return true;
                }

                break;
            }

            case OVERWRITE_OVER:   // In this case do nothing : 'convert' default mode...
                item->setDidOverWrite(true);
                break;

            default:
            {
                endProcess();
                return true;
            }
        }
    }

    m_ProcessusProc = new KProcess(this);
    m_ProcessusProc->setOutputChannelMode(KProcess::MergedChannels);
    initProcess(m_ProcessusProc, item, targetAlbum);
    m_commandLine = m_ProcessusProc->program().join(" ");

    item->changeOutputMess(m_commandLine + "\n\n");

    connect(m_ProcessusProc, SIGNAL(finished(int,QProcess::ExitStatus)),
            this, SLOT(slotFinished()));

    connect(m_ProcessusProc, SIGNAL(readyRead()),
            this, SLOT(slotReadyRead()));

    m_ProcessusProc->start();
    if (!m_ProcessusProc->waitForStarted())
    {
        KMessageBox::error(this, i18n("Cannot start 'convert' program from 'ImageMagick' package;\n"
                                      "please check your installation."));
        delete m_ProcessusProc;
        m_ProcessusProc = 0;
        return false;
    }

    return true;
}
Beispiel #12
0
//
// AbiPaint editImage
// ------------------
//   This is the function that we actually call to invoke the image editor.
//
//   parameters are:
//     AV_View* v
//     EV_EditMethodCallData *d
//
static DECLARE_ABI_PLUGIN_METHOD(editImage)
{
	UT_UNUSED(v);
    // Get the current view that the user is in.
    XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame();
    FV_View* pView = static_cast<FV_View*>(pFrame->getCurrentView());

//
// get values from preference (initial plugin execution should have set sensible defaults)
//
	UT_String imageApp;  // holds MAXPATH\appName <space> MAXPATH\imagefilename
	bool bLeaveImageAsPNG;

	// read stuff from the preference value
	if (!prefsScheme->getValue(ABIPAINT_PREF_KEY_szProgramName, imageApp))
	{
		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
		getDefaultApp(imageApp, bLeaveImageAsPNG);
	}
	
	// now that we have program name, try to get other flag (allows overriding default value)
	// Note: we allow overriding, otherwise if we don't adhere to user's setting
	//       then the use BMP or not menu should be greyed to note it has no effect
	prefsScheme->getValueBool(ABIPAINT_PREF_KEY_bLeaveImageAsPNG, &bLeaveImageAsPNG);


//
// generate a temp file name...
//
	char *szTempFileName = NULL;
	GError *err = NULL;
	gint fp = g_file_open_tmp ("XXXXXX", &szTempFileName, &err);
	if (err) {
		g_warning ("%s", err->message);
		g_error_free (err); err = NULL;
		return FALSE;
	}
	close(fp);

	UT_String szTmpPng = szTempFileName;
	szTmpPng += ".png";
	UT_String szTmp = szTmpPng; // default: our temp file is the created png file
	
	PT_DocPosition pos = pView->saveSelectedImage((const char *)szTmpPng.c_str());
	if(pos == 0)
	{
		remove(szTempFileName);
		g_free (szTempFileName); szTempFileName = NULL;
		pFrame->showMessageBox("You must select an Image before editing it", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
		return false;
	}

#ifdef ENABLE_BMP
//
// Convert png into bmp for best compatibility with Windows programs
// NOTE: probably looses detail/information though!!! so if possible use PNG
//
	if (!bLeaveImageAsPNG)
	{
		szTmp = szTempFileName;
		szTmp += ".bmp";	// our temp file is a bmp file

		if (convertPNG2BMP(szTmpPng.c_str(), szTmp.c_str()))
		{
			pFrame->showMessageBox("Unable to convert PNG image data to BMP for external program use!", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);

			remove(szTempFileName);
			g_free (szTempFileName); szTempFileName = NULL;
			remove(szTmpPng.c_str());
			return false;
		}
		// remove(szTmpPng.c_str());

	}
#endif
	
	// remove the temp file (that lacks proper extension)
	remove(szTempFileName);
	g_free (szTempFileName); szTempFileName = NULL;

//
// Get the initial file status.
//
	struct stat myFileStat;
	int ok = stat(szTmp.c_str(),&myFileStat);
	if(ok < 0)
	{
		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
		remove(szTmpPng.c_str());
		remove(szTmp.c_str());	// should silently fail if exporting as PNG file
		return false;
	}
	time_t mod_time = myFileStat.st_mtime;

//	
// Fire up the image editor...
//
	ProcessInfo procInfo;
	if (!createChildProcess(imageApp.c_str(), szTmp.c_str(), &procInfo))

	{
		UT_String msg = "Unable to run program: ";  msg += imageApp + " " + szTmp;
		pFrame->showMessageBox(msg.c_str(), XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);

		// failed to spawn stuff, so do some cleanup and return failure
		remove(szTmpPng.c_str());
		remove(szTmp.c_str());	// should silently fail if exporting as PNG file
		return false;
	}

	lockGUI(d);

	while (isProcessStillAlive(procInfo))
	{
		UT_usleep(10000); // wait 10 milliseconds
		pFrame->nullUpdate();
		ok = stat(szTmp.c_str(),&myFileStat);
		if(ok == 0)
		{ 
			if(myFileStat.st_mtime != mod_time)
			{
				// wait for changes to settle (program done writing changes)
				// we use both modified time & file size, but really we
				// could just use file size as mod time doesn't appear to change for small images
				mod_time = myFileStat.st_mtime;
				off_t size = myFileStat.st_size;
				UT_usleep(100000); // wait 100 milliseconds (so program may have time to write something)
				ok = stat(szTmp.c_str(),&myFileStat);
				while((mod_time != myFileStat.st_mtime) || !size || (size > 0 && size != myFileStat.st_size))
				{
					mod_time = myFileStat.st_mtime;
					size = myFileStat.st_size;
					ok = stat(szTmp.c_str(),&myFileStat);
					UT_usleep(500000); // wait a while, let program write its data

					// just make sure the program is still running, otherwise we could get stuck in a loop
					if (!isProcessStillAlive(procInfo))
					{
						pFrame->showMessageBox("External image editor appears to have been terminated unexpectedly.", 
								XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
						//procInfo.hProcess = 0;
						goto Cleanup;
					}
				}
				mod_time = myFileStat.st_mtime;
				UT_usleep(100000); // wait a while just to make sure program is done with file

//
// OK replace the current image with this.
//
				IEGraphicFileType iegft = IEGFT_Unknown;
				FG_Graphic* pFG;
		
				UT_Error errorCode;
		
#ifdef ENABLE_BMP
//
// Convert bmp back to png (as we can not assume AbiWord has builtin BMP support [as its now an optional plugin])
// NOTE: probably looses detail/information though!!! so if possible use only PNG
//
				if (!bLeaveImageAsPNG)
				{
					if (convertBMP2PNG(szTmp.c_str(), szTmpPng.c_str()))
					{
						pFrame->showMessageBox("Unable to convert BMP image data back to PNG for AbiWord to import!", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
						UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
						goto Cleanup;
					}
				}
#endif

				errorCode = IE_ImpGraphic::loadGraphic(szTmpPng.c_str(), iegft, &pFG);
				if(errorCode)
				{
					UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
					pFrame->showMessageBox("Error making pFG. Could not put image back into Abiword", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
					goto Cleanup;
				}

				unlockGUI(d);

				pView->cmdUnselectSelection();
				pView->setPoint(pos);
				pView->extSelHorizontal(true, 1); // move point forward one
				errorCode = pView->cmdInsertGraphic(pFG);
				if (errorCode)
				{
					pFrame->showMessageBox("Could not put image back into Abiword", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK);
					UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
					DELETEP(pFG);
					goto Cleanup;
				}
				DELETEP(pFG);
//
// Reselect the image
//
				pView->setPoint(pos);
				pView->extSelHorizontal(true, 1); // move point forward one

				lockGUI(d);
			}
		}
	}

//
// Normal exit, delete the tempfile and return success
//
	remove(szTmpPng.c_str());
	remove(szTmp.c_str());	// should silently fail if exporting as PNG file
	unlockGUI(d);
	return true;

//
// Something went wrong.
//
 Cleanup: 
	remove(szTmpPng.c_str());
	remove(szTmp.c_str());	// should silently fail if exporting as PNG file
	unlockGUI(d);
//
// Kill the image editor.
//
	endProcess(procInfo);
	return false;
}