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.
311 lines
7.3 KiB
311 lines
7.3 KiB
/*
|
|
* Copyright Johannes Sixt
|
|
* This file is licensed under the GNU General Public License Version 2.
|
|
* See the file COPYING in the toplevel directory of the source directory.
|
|
*/
|
|
|
|
#include "procattach.h"
|
|
#include <tqlistview.h>
|
|
#include <tqtoolbutton.h>
|
|
#include <tqlineedit.h>
|
|
#include <kprocess.h>
|
|
#include <ctype.h>
|
|
#include <tdeapplication.h>
|
|
#include <kiconloader.h>
|
|
#include <tdelocale.h> /* i18n */
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
|
|
ProcAttachPS::ProcAttachPS(TQWidget* parent) :
|
|
ProcAttachBase(parent),
|
|
m_pidCol(-1),
|
|
m_ppidCol(-1)
|
|
{
|
|
m_ps = new TDEProcess;
|
|
connect(m_ps, SIGNAL(receivedStdout(TDEProcess*, char*, int)),
|
|
this, SLOT(slotTextReceived(TDEProcess*, char*, int)));
|
|
connect(m_ps, SIGNAL(processExited(TDEProcess*)),
|
|
this, SLOT(slotPSDone()));
|
|
|
|
TQIconSet icon = SmallIconSet("clear_left");
|
|
filterClear->setIconSet(icon);
|
|
|
|
processList->setColumnWidth(0, 300);
|
|
processList->setColumnWidthMode(0, TQListView::Manual);
|
|
processList->setColumnAlignment(1, TQt::AlignRight);
|
|
processList->setColumnAlignment(2, TQt::AlignRight);
|
|
|
|
// set the command line
|
|
static const char* const psCommand[] = {
|
|
#ifdef PS_COMMAND
|
|
PS_COMMAND,
|
|
#else
|
|
"/bin/false",
|
|
#endif
|
|
0
|
|
};
|
|
for (int i = 0; psCommand[i] != 0; i++) {
|
|
*m_ps << psCommand[i];
|
|
}
|
|
|
|
runPS();
|
|
}
|
|
|
|
ProcAttachPS::~ProcAttachPS()
|
|
{
|
|
delete m_ps; // kills a running ps
|
|
}
|
|
|
|
void ProcAttachPS::runPS()
|
|
{
|
|
// clear the parse state from previous runs
|
|
m_token = "";
|
|
m_line.clear();
|
|
m_pidCol = -1;
|
|
m_ppidCol = -1;
|
|
|
|
m_ps->start(TDEProcess::NotifyOnExit, TDEProcess::Stdout);
|
|
}
|
|
|
|
void ProcAttachPS::slotTextReceived(TDEProcess*, char* buffer, int buflen)
|
|
{
|
|
const char* end = buffer+buflen;
|
|
while (buffer < end)
|
|
{
|
|
// check new line
|
|
if (*buffer == '\n')
|
|
{
|
|
// push a tokens onto the line
|
|
if (!m_token.isEmpty()) {
|
|
m_line.push_back(TQString::fromLatin1(m_token));
|
|
m_token = "";
|
|
}
|
|
// and insert the line in the list
|
|
pushLine();
|
|
m_line.clear();
|
|
++buffer;
|
|
}
|
|
// blanks: the last column gets the rest of the line, including blanks
|
|
else if ((m_pidCol < 0 || int(m_line.size()) < processList->columns()-1) &&
|
|
isspace(*buffer))
|
|
{
|
|
// push a token onto the line
|
|
if (!m_token.isEmpty()) {
|
|
m_line.push_back(TQString::fromLatin1(m_token));
|
|
m_token = "";
|
|
}
|
|
do {
|
|
++buffer;
|
|
} while (buffer < end && isspace(*buffer));
|
|
}
|
|
// tokens
|
|
else
|
|
{
|
|
const char* start = buffer;
|
|
do {
|
|
++buffer;
|
|
} while (buffer < end && !isspace(*buffer));
|
|
// append to the current token
|
|
m_token += TQCString(start, buffer-start+1); // must count the '\0'
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProcAttachPS::pushLine()
|
|
{
|
|
if (m_line.size() < 3) // we need the PID, PPID, and COMMAND columns
|
|
return;
|
|
|
|
if (m_pidCol < 0)
|
|
{
|
|
// create columns if we don't have them yet
|
|
bool allocate = processList->columns() == 3;
|
|
|
|
// we assume that the last column is the command
|
|
m_line.pop_back();
|
|
|
|
for (uint i = 0; i < m_line.size(); i++) {
|
|
// we don't allocate the PID and PPID columns,
|
|
// but we need to know where in the ps output they are
|
|
if (m_line[i] == "PID") {
|
|
m_pidCol = i;
|
|
} else if (m_line[i] == "PPID") {
|
|
m_ppidCol = i;
|
|
} else if (allocate) {
|
|
processList->addColumn(m_line[i]);
|
|
// these columns are normally numbers
|
|
processList->setColumnAlignment(processList->columns()-1,
|
|
TQt::AlignRight);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// insert a line
|
|
// find the parent process
|
|
TQListViewItem* parent = 0;
|
|
if (m_ppidCol >= 0 && m_ppidCol < int(m_line.size())) {
|
|
parent = processList->findItem(m_line[m_ppidCol], 1);
|
|
}
|
|
|
|
// we assume that the last column is the command
|
|
TQListViewItem* item;
|
|
if (parent == 0) {
|
|
item = new TQListViewItem(processList, m_line.back());
|
|
} else {
|
|
item = new TQListViewItem(parent, m_line.back());
|
|
}
|
|
item->setOpen(true);
|
|
m_line.pop_back();
|
|
int k = 3;
|
|
for (uint i = 0; i < m_line.size(); i++)
|
|
{
|
|
// display the pid and ppid columns' contents in columns 1 and 2
|
|
if (int(i) == m_pidCol)
|
|
item->setText(1, m_line[i]);
|
|
else if (int(i) == m_ppidCol)
|
|
item->setText(2, m_line[i]);
|
|
else
|
|
item->setText(k++, m_line[i]);
|
|
}
|
|
|
|
if (m_ppidCol >= 0 && m_pidCol >= 0) { // need PID & PPID for this
|
|
/*
|
|
* It could have happened that a process was earlier inserted,
|
|
* whose parent process is the current process. Such processes
|
|
* were placed at the root. Here we go through all root items
|
|
* and check whether we must reparent them.
|
|
*/
|
|
TQListViewItem* i = processList->firstChild();
|
|
while (i != 0)
|
|
{
|
|
// advance before we reparent the item
|
|
TQListViewItem* it = i;
|
|
i = i->nextSibling();
|
|
if (it->text(2) == m_line[m_pidCol]) {
|
|
processList->takeItem(it);
|
|
item->insertItem(it);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProcAttachPS::slotPSDone()
|
|
{
|
|
filterEdited(filterEdit->text());
|
|
}
|
|
|
|
TQString ProcAttachPS::text() const
|
|
{
|
|
TQListViewItem* item = processList->selectedItem();
|
|
|
|
if (item == 0)
|
|
return TQString();
|
|
|
|
return item->text(1);
|
|
}
|
|
|
|
void ProcAttachPS::refresh()
|
|
{
|
|
if (!m_ps->isRunning())
|
|
{
|
|
processList->clear();
|
|
buttonOk->setEnabled(false); // selection was cleared
|
|
runPS();
|
|
}
|
|
}
|
|
|
|
void ProcAttachPS::filterEdited(const TQString& text)
|
|
{
|
|
TQListViewItem* i = processList->firstChild();
|
|
if (i) {
|
|
setVisibility(i, text);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the visibility of \a i and
|
|
* returns whether it was made visible.
|
|
*/
|
|
bool ProcAttachPS::setVisibility(TQListViewItem* i, const TQString& text)
|
|
{
|
|
bool visible = false;
|
|
for (TQListViewItem* j = i->firstChild(); j; j = j->nextSibling())
|
|
{
|
|
if (setVisibility(j, text))
|
|
visible = true;
|
|
}
|
|
// look for text in the process name and in the PID
|
|
visible = visible || text.isEmpty() ||
|
|
i->text(0).find(text, 0, false) >= 0 ||
|
|
i->text(1).find(text) >= 0;
|
|
|
|
i->setVisible(visible);
|
|
|
|
// disable the OK button if the selected item becomes invisible
|
|
if (i->isSelected())
|
|
buttonOk->setEnabled(visible);
|
|
|
|
return visible;
|
|
}
|
|
|
|
void ProcAttachPS::selectedChanged()
|
|
{
|
|
buttonOk->setEnabled(processList->selectedItem() != 0);
|
|
}
|
|
|
|
|
|
ProcAttach::ProcAttach(TQWidget* parent) :
|
|
TQDialog(parent, "procattach", true),
|
|
m_label(this, "label"),
|
|
m_processId(this, "procid"),
|
|
m_buttonOK(this, "ok"),
|
|
m_buttonCancel(this, "cancel"),
|
|
m_layout(this, 8),
|
|
m_buttons(4)
|
|
{
|
|
TQString title = kapp->caption();
|
|
title += i18n(": Attach to process");
|
|
setCaption(title);
|
|
|
|
m_label.setMinimumSize(330, 24);
|
|
m_label.setText(i18n("Specify the process number to attach to:"));
|
|
|
|
m_processId.setMinimumSize(330, 24);
|
|
m_processId.setMaxLength(100);
|
|
m_processId.setFrame(true);
|
|
|
|
m_buttonOK.setMinimumSize(100, 30);
|
|
connect(&m_buttonOK, SIGNAL(clicked()), SLOT(accept()));
|
|
m_buttonOK.setText(i18n("OK"));
|
|
m_buttonOK.setDefault(true);
|
|
|
|
m_buttonCancel.setMinimumSize(100, 30);
|
|
connect(&m_buttonCancel, SIGNAL(clicked()), SLOT(reject()));
|
|
m_buttonCancel.setText(i18n("Cancel"));
|
|
|
|
m_layout.addWidget(&m_label);
|
|
m_layout.addWidget(&m_processId);
|
|
m_layout.addLayout(&m_buttons);
|
|
m_layout.addStretch(10);
|
|
m_buttons.addStretch(10);
|
|
m_buttons.addWidget(&m_buttonOK);
|
|
m_buttons.addSpacing(40);
|
|
m_buttons.addWidget(&m_buttonCancel);
|
|
m_buttons.addStretch(10);
|
|
|
|
m_layout.activate();
|
|
|
|
m_processId.setFocus();
|
|
resize(350, 120);
|
|
}
|
|
|
|
ProcAttach::~ProcAttach()
|
|
{
|
|
}
|
|
|
|
#include "procattach.moc"
|